PHPStan: require iterable types (#3936)

* phpstan: require iterable types

* add link on relative path and line

* fix missing class type

* typed array in Rector code + add data provide support resolver

* remove duplicated set

* drop unused yaml ecs config

* add out-of-the-box directory for 3rd party packages

* static fixes

* [rector] static fixes

* [cs] static fixes

* [rector] [cs] static fixes

* generic types

Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
Tomas Votruba 2020-08-11 12:59:04 +02:00 committed by GitHub
parent e4af8cc721
commit 1c4b510513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
186 changed files with 1208 additions and 405 deletions

View File

@ -46,6 +46,7 @@ expectedArguments(
\Rector\NodeTypeResolver\Node\AttributeKey::COMMENTS,
\Rector\NodeTypeResolver\Node\AttributeKey::VIRTUAL_NODE,
\Rector\NodeTypeResolver\Node\AttributeKey::CLOSURE_NODE,
\Rector\NodeTypeResolver\Node\AttributeKey::PARAMETER_POSITION,
);
expectedArguments(
@ -77,6 +78,7 @@ expectedArguments(
\Rector\NodeTypeResolver\Node\AttributeKey::COMMENTS,
\Rector\NodeTypeResolver\Node\AttributeKey::VIRTUAL_NODE,
\Rector\NodeTypeResolver\Node\AttributeKey::CLOSURE_NODE,
\Rector\NodeTypeResolver\Node\AttributeKey::PARAMETER_POSITION,
);
expectedArguments(

View File

@ -8,6 +8,10 @@ use Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector;
use Rector\Doctrine\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
/**
* @see https://tomasvotruba.com/blog/2017/10/16/how-to-use-repository-with-doctrine-as-service-in-symfony/
* @see https://tomasvotruba.com/blog/2018/04/02/rectify-turn-repositories-to-services-in-symfony/
*/
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
@ -19,4 +23,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(ReplaceParentRepositoryCallsByRepositoryPropertyRector::class);
$services->set(RemoveRepositoryFromEntityAnnotationRector::class);
$services->set(ReplaceParentRepositoryCallsByRepositoryPropertyRector::class);
};

View File

@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Architecture\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
use Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
use Rector\Doctrine\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
/**
* @see https://tomasvotruba.com/blog/2017/10/16/how-to-use-repository-with-doctrine-as-service-in-symfony/
* @see https://tomasvotruba.com/blog/2018/04/02/rectify-turn-repositories-to-services-in-symfony/
*/
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ReplaceParentRepositoryCallsByRepositoryPropertyRector::class);
$services->set(MoveRepositoryFromParentToConstructorRector::class);
$services->set(RemoveRepositoryFromEntityAnnotationRector::class);
};

View File

@ -1,3 +0,0 @@
# for back compatibility
imports:
- { resource: 'ecs-after-rector.php' }

View File

@ -9,6 +9,7 @@ use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer;
use PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocTypesFixer;
use PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer;
use PhpCsFixer\Fixer\ReturnNotation\ReturnAssignmentFixer;
use PhpCsFixer\Fixer\Strict\StrictComparisonFixer;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer;
@ -77,6 +78,10 @@ return static function (ContainerConfigurator $containerConfigurator): void {
'*TypeResolverTest.php',
],
UnaryOperatorSpacesFixer::class => null,
// breaks on-purpose annotated variables
ReturnAssignmentFixer::class => null,
StrictComparisonFixer::class => [__DIR__ . '/packages/polyfill/src/ConditionEvaluator.php'],
]);

View File

@ -32,6 +32,11 @@ final class AttributeAwareDataProviderTagValueNode implements PhpDocTagValueNode
return $this->method;
}
public function getMethodName(): string
{
return trim($this->method, '()');
}
public function changeMethod(string $method): void
{
$this->method = $method;

View File

@ -35,7 +35,7 @@ final class AttributeAwareMethodTagValueNodeFactory implements AttributeNodeAwar
*/
public function create(Node $node, string $docContent): AttributeAwareNodeInterface
{
$returnType = $this->createAttributeAwareReturnType($node, $docContent);
$returnType = $this->attributizeReturnType($node, $docContent);
foreach ($node->parameters as $key => $parameter) {
$node->parameters[$key] = $this->attributeAwareNodeFactory->createFromNode($parameter, $docContent);
@ -55,15 +55,19 @@ final class AttributeAwareMethodTagValueNodeFactory implements AttributeNodeAwar
$this->attributeAwareNodeFactory = $attributeAwareNodeFactory;
}
/**
* @return TypeNode&AttributeAwareNodeInterface
*/
private function createAttributeAwareReturnType(MethodTagValueNode $methodTagValueNode, string $docContent)
{
private function attributizeReturnType(
MethodTagValueNode $methodTagValueNode,
string $docContent
): ?AttributeAwareNodeInterface {
if ($methodTagValueNode->returnType !== null) {
return $this->attributeAwareNodeFactory->createFromNode($methodTagValueNode->returnType, $docContent);
return $this->createAttributeAwareReturnType($methodTagValueNode->returnType, $docContent);
}
return $methodTagValueNode->returnType;
return null;
}
private function createAttributeAwareReturnType(TypeNode $typeNode, string $docContent): AttributeAwareNodeInterface
{
return $this->attributeAwareNodeFactory->createFromNode($typeNode, $docContent);
}
}

View File

@ -21,6 +21,7 @@ final class AnnotationItemsResolver
/**
* @param object|Annotation|mixed[] $annotationOrItems
* @return mixed[]
*/
public function resolve($annotationOrItems): array
{

View File

@ -153,7 +153,7 @@ final class PhpDocInfo
}
/**
* @return PhpDocTagNode[]
* @return PhpDocTagNode[]|AttributeAwareNodeInterface[]
*/
public function getTagsByName(string $name): array
{

View File

@ -31,6 +31,9 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
*/
protected $tagValueNodeConfiguration;
/**
* @param mixed[] $items
*/
public function __construct(array $items, ?string $originalContent = null)
{
$this->items = $items;
@ -144,6 +147,9 @@ abstract class AbstractTagValueNode implements AttributeAwareNodeInterface, PhpD
);
}
/**
* @return mixed[]|string[]
*/
protected function filterOutMissingItems(array $contentItems): array
{
if ($this->tagValueNodeConfiguration->getOrderedVisibleItems() === null) {

View File

@ -38,6 +38,9 @@ final class EntityTagValueNode extends AbstractDoctrineTagValueNode implements P
return $this->printItemsToAttributeString($items);
}
/**
* @return mixed[]
*/
private function createAttributeItems(): array
{
$items = $this->items;

View File

@ -107,6 +107,9 @@ final class TableTagValueNode extends AbstractDoctrineTagValueNode implements Si
return 'name';
}
/**
* @return mixed[]
*/
private function addCustomItems(array $items): array
{
if ($this->indexes !== []) {

View File

@ -38,6 +38,9 @@ final class ColumnTagValueNode extends AbstractDoctrineTagValueNode implements P
return $this->printItemsToAttributeString($items);
}
/**
* @return mixed[]
*/
private function createAttributeItems(): array
{
$items = $this->items;

View File

@ -60,6 +60,9 @@ final class JoinColumnTagValueNode extends AbstractDoctrineTagValueNode implemen
return $this->printItemsToAttributeString($this->createAttributeItems());
}
/**
* @return mixed[]
*/
private function createAttributeItems(): array
{
$items = $this->items;

View File

@ -122,6 +122,9 @@ final class JoinTableTagValueNode extends AbstractDoctrineTagValueNode implement
return $joinTableAttributeContent;
}
/**
* @return string[]
*/
private function createItems(): array
{
$items = [];

View File

@ -80,6 +80,9 @@ final class ManyToManyTagValueNode extends AbstractDoctrineTagValueNode implemen
return $this->printItemsToAttributeString($this->createAttributeItems());
}
/**
* @return mixed[]
*/
private function createAttributeItems(): array
{
$items = $this->items;

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocNode\PHPUnit;
use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode;
final class DataProviderTagValueNode extends AbstractTagValueNode
{
}

View File

@ -12,6 +12,9 @@ use Rector\BetterPhpDocParser\ValueObject\TagValueNodeConfiguration;
*/
trait PrintTagValueNodeTrait
{
/**
* @return mixed[]
*/
protected function makeKeysExplicit(array $items): array
{
foreach ($items as $key => $contentItem) {
@ -32,6 +35,7 @@ trait PrintTagValueNodeTrait
/**
* @param string[] $skipKeys
* @return mixed[]
*/
protected function completeItemsQuotes(array $items, array $skipKeys = []): array
{

View File

@ -112,6 +112,9 @@ final class TagValueNodeConfiguration
return $this->hasClosingBracket;
}
/**
* @return mixed[]
*/
public function getKeysByQuotedStatus(): array
{
return $this->keysByQuotedStatus;

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Rector\ChangesReporting\Application;
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PHPStan\AnalysedCodeException;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\ConsoleDiffer\DifferAndFormatter;
@ -87,7 +86,7 @@ final class ErrorAndDiffCollector
}
/**
* @return Node[]|Stmt[]
* @return Node[]
*/
public function getRemovedNodes(): array
{

View File

@ -128,12 +128,15 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface
private function reportErrors(array $errors): void
{
foreach ($errors as $error) {
$errorMessage = $error->getMessage();
$errorMessage = $this->normalizePathsToRelativeWithLine($errorMessage);
$message = sprintf(
'Could not process "%s" file%s, due to: %s"%s".',
$error->getFileInfo()->getRelativeFilePathFromCwd(),
$error->getRectorClass() ? ' by "' . $error->getRectorClass() . '"' : '',
PHP_EOL,
$error->getMessage()
$errorMessage
);
if ($error->getLine()) {
@ -154,6 +157,12 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface
$this->reportRemovedNodes($errorAndDiffCollector);
}
private function normalizePathsToRelativeWithLine(string $errorMessage): string
{
$errorMessage = Strings::replace($errorMessage, '#' . preg_quote(getcwd(), '#') . '/#');
return $errorMessage = Strings::replace($errorMessage, '# on line #', ':');
}
private function reportRemovedNodes(ErrorAndDiffCollector $errorAndDiffCollector): void
{
if ($errorAndDiffCollector->getRemovedNodeCount() === 0) {

View File

@ -18,6 +18,9 @@ final class StaticInMemoryProbeStorage implements ProbeStorageInterface
self::$probeItems[] = $probeItem;
}
/**
* @return string[]
*/
public static function getProbeItems(): array
{
// remove empty values

View File

@ -60,6 +60,9 @@ final class ClassChildAnalyzer
return false;
}
/**
* @return class-string[]
*/
private function getChildClasses(Class_ $class): array
{
$className = $class->getAttribute(AttributeKey::CLASS_NAME);

View File

@ -7,7 +7,7 @@ namespace Rector\FamilyTree\Reflection;
final class FamilyRelationsAnalyzer
{
/**
* @return string[]
* @return class-string[]
*/
public function getChildrenOfClass(string $parentClass): array
{

View File

@ -23,6 +23,8 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* All parsed nodes grouped type
* @template TNodeType of \PhpParser\Node
* @see https://phpstan.org/blog/generics-in-php-using-phpdocs
*/
final class ParsedNodeCollector
{
@ -57,7 +59,7 @@ final class ParsedNodeCollector
private $constantsByType = [];
/**
* @var Node[][]
* @var array<array<TNodeType>>
*/
private $simpleParsedNodesByType = [];
@ -82,9 +84,8 @@ final class ParsedNodeCollector
}
/**
* @template T of object
* @param class-string<T> $type
* @return Node[]|iterable<T>
* @param class-string<TNodeType> $type
* @return array<TNodeType>
*/
public function getNodesByType(string $type): array
{
@ -197,7 +198,6 @@ final class ParsedNodeCollector
{
$newNodesByClass = [];
/** @var New_[] $news */
$news = $this->getNodesByType(New_::class);
foreach ($news as $new) {

View File

@ -153,6 +153,7 @@ final class NodeNameResolver
/**
* @param Name[]|Node[] $nodes
* @return string[]
*/
public function getNames(array $nodes): array
{

View File

@ -10,7 +10,7 @@ use PHPStan\Type\Type;
interface NodeTypeResolverInterface
{
/**
* @return string[]
* @return class-string[]
*/
public function getNodeClasses(): array;

View File

@ -155,6 +155,9 @@ final class PHPStanServicesFactory
return $this->container->getByType(TypeNodeResolver::class);
}
/**
* @return mixed[]
*/
private function appendPhpstanPHPUnitExtensionIfExists(
string $currentWorkingDirectory,
array $additionalConfigFiles

View File

@ -181,4 +181,9 @@ final class AttributeKey
* @var string
*/
public const CLOSURE_NODE = Closure::class;
/**
* @var string
*/
public const PARAMETER_POSITION = 'parameter_position';
}

View File

@ -12,6 +12,7 @@ use PhpParser\NodeVisitor\NodeConnectingVisitor;
use Rector\Core\Configuration\Configuration;
use Rector\NodeCollector\NodeVisitor\NodeCollectorNodeVisitor;
use Rector\NodeTypeResolver\NodeVisitor\FileInfoNodeVisitor;
use Rector\NodeTypeResolver\NodeVisitor\FunctionLikeParamPositionNodeVisitor;
use Rector\NodeTypeResolver\NodeVisitor\FunctionMethodAndClassNodeVisitor;
use Rector\NodeTypeResolver\NodeVisitor\NamespaceNodeVisitor;
use Rector\NodeTypeResolver\NodeVisitor\PhpDocInfoNodeVisitor;
@ -71,6 +72,11 @@ final class NodeScopeAndMetadataDecorator
*/
private $nodeConnectingVisitor;
/**
* @var FunctionLikeParamPositionNodeVisitor
*/
private $functionLikeParamPositionNodeVisitor;
public function __construct(
CloningVisitor $cloningVisitor,
Configuration $configuration,
@ -81,7 +87,8 @@ final class NodeScopeAndMetadataDecorator
PHPStanNodeScopeResolver $phpStanNodeScopeResolver,
PhpDocInfoNodeVisitor $phpDocInfoNodeVisitor,
StatementNodeVisitor $statementNodeVisitor,
NodeConnectingVisitor $nodeConnectingVisitor
NodeConnectingVisitor $nodeConnectingVisitor,
FunctionLikeParamPositionNodeVisitor $functionLikeParamPositionNodeVisitor
) {
$this->phpStanNodeScopeResolver = $phpStanNodeScopeResolver;
$this->cloningVisitor = $cloningVisitor;
@ -93,6 +100,7 @@ final class NodeScopeAndMetadataDecorator
$this->configuration = $configuration;
$this->phpDocInfoNodeVisitor = $phpDocInfoNodeVisitor;
$this->nodeConnectingVisitor = $nodeConnectingVisitor;
$this->functionLikeParamPositionNodeVisitor = $functionLikeParamPositionNodeVisitor;
}
/**
@ -132,6 +140,7 @@ final class NodeScopeAndMetadataDecorator
$nodeTraverser->addVisitor($this->functionMethodAndClassNodeVisitor);
$nodeTraverser->addVisitor($this->namespaceNodeVisitor);
$nodeTraverser->addVisitor($this->phpDocInfoNodeVisitor);
$nodeTraverser->addVisitor($this->functionLikeParamPositionNodeVisitor);
$nodes = $nodeTraverser->traverse($nodes);

View File

@ -36,7 +36,7 @@ use Rector\TypeDeclaration\PHPStan\Type\ObjectTypeSpecifier;
final class NodeTypeResolver
{
/**
* @var NodeTypeResolverInterface[]
* @var array<class-string, NodeTypeResolverInterface>
*/
private $nodeTypeResolvers = [];

View File

@ -54,8 +54,11 @@ final class ClassAndInterfaceTypeResolver implements NodeTypeResolverInterface
return new MixedType();
}
/** @var ClassReflection $classReflection */
/** @var ClassReflection|null $classReflection */
$classReflection = $nodeScope->getClassReflection();
if ($classReflection === null) {
return new MixedType();
}
$classTypes = $this->classReflectionTypesResolver->resolve($classReflection);

View File

@ -13,6 +13,7 @@ use PhpParser\NodeTraverser;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
@ -131,15 +132,23 @@ final class ParamTypeResolver implements NodeTypeResolverInterface
private function resolveFromFunctionDocBlock(Param $param): Type
{
/** @var FunctionLike $parentNode */
$parentNode = $param->getAttribute(AttributeKey::PARENT_NODE);
$phpDocInfo = $this->getFunctionLikePhpDocInfo($param);
if ($phpDocInfo === null) {
return new MixedType();
}
/** @var string $paramName */
$paramName = $this->nodeNameResolver->getName($param);
/** @var PhpDocInfo $phpDocInfo */
$phpDocInfo = $parentNode->getAttribute(AttributeKey::PHP_DOC_INFO);
return $phpDocInfo->getParamType($paramName);
}
private function getFunctionLikePhpDocInfo(Param $param): ?PhpDocInfo
{
$parentNode = $param->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof FunctionLike) {
throw new ShouldNotHappenException();
}
return $parentNode->getAttribute(AttributeKey::PHP_DOC_INFO);
}
}

View File

@ -21,6 +21,9 @@ use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
final class ScalarTypeResolver implements NodeTypeResolverInterface
{
/**
* @return class-string[]
*/
public function getNodeClasses(): array
{
return [Scalar::class];

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Rector\NodeTypeResolver\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\FunctionLike;
use PhpParser\NodeVisitorAbstract;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class FunctionLikeParamPositionNodeVisitor extends NodeVisitorAbstract
{
/**
* @return Node
*/
public function enterNode(Node $node): ?Node
{
if (! $node instanceof FunctionLike) {
return null;
}
foreach ($node->getParams() as $position => $param) {
$param->setAttribute(AttributeKey::PARAMETER_POSITION, $position);
}
return $node;
}
}

View File

@ -88,10 +88,7 @@ final class FunctionMethodAndClassNodeVisitor extends NodeVisitorAbstract
return null;
}
/**
* @return int|Node|void|null
*/
public function enterNode(Node $node)
public function enterNode(Node $node): ?Node
{
$this->processClass($node);
$this->processMethod($node);

View File

@ -20,10 +20,7 @@ final class PhpDocInfoNodeVisitor extends NodeVisitorAbstract
$this->phpDocInfoFactory = $phpDocInfoFactory;
}
/**
* @return int|Node|void|null
*/
public function enterNode(Node $node)
public function enterNode(Node $node): ?Node
{
// also binds to the node
$this->phpDocInfoFactory->createFromNode($node);

View File

@ -7,7 +7,6 @@ namespace Rector\NodeTypeResolver\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PhpParser\NodeVisitorAbstract;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class StatementNodeVisitor extends NodeVisitorAbstract
@ -28,16 +27,12 @@ final class StatementNodeVisitor extends NodeVisitorAbstract
return null;
}
/**
* @return int|Node|void|null
*/
public function enterNode(Node $node)
public function enterNode(Node $node): ?Node
{
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parent === null) {
if (! $node instanceof Stmt) {
return null;
// throw new ShouldNotHappenException('Only statement can appear at top level');
}
$node->setAttribute(AttributeKey::PREVIOUS_STATEMENT, $this->previousStmt);
@ -45,7 +40,7 @@ final class StatementNodeVisitor extends NodeVisitorAbstract
$this->previousStmt = $node;
}
if (isset($node->stmts)) {
if (property_exists($node, 'stmts')) {
$previous = $node;
foreach ((array) $node->stmts as $stmt) {
$stmt->setAttribute(AttributeKey::PREVIOUS_STATEMENT, $previous);
@ -53,15 +48,21 @@ final class StatementNodeVisitor extends NodeVisitorAbstract
$previous = $stmt;
}
}
if ($parent && ! $node->getAttribute(AttributeKey::CURRENT_STATEMENT)) {
$currentStmt = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
if ($parent && ! $currentStmt) {
$node->setAttribute(
AttributeKey::PREVIOUS_STATEMENT,
$parent->getAttribute(AttributeKey::PREVIOUS_STATEMENT)
);
$node->setAttribute(
AttributeKey::CURRENT_STATEMENT,
$parent->getAttribute(AttributeKey::CURRENT_STATEMENT)
);
}
return null;
}
}

View File

@ -38,10 +38,7 @@ final class RemoveDeepChainMethodCallNodeVisitor extends NodeVisitorAbstract
$this->nestedChainMethodCallLimit = $nestedChainMethodCallLimit;
}
/**
* @return int|Node|null
*/
public function enterNode(Node $node)
public function enterNode(Node $node): ?int
{
if (! $node instanceof Expression) {
return null;
@ -60,7 +57,7 @@ final class RemoveDeepChainMethodCallNodeVisitor extends NodeVisitorAbstract
}
/**
* @return int|Node|Node[]|null
* @return Nop|Node
*/
public function leaveNode(Node $node)
{

View File

@ -16,7 +16,7 @@ use Rector\Polyfill\ValueObject\VersionCompareCondition;
final class ConditionEvaluator
{
/**
* @return bool|int|mixed|null
* @return bool|null|int
*/
public function evaluate(ConditionInterface $condition)
{

View File

@ -57,12 +57,18 @@ final class NodesToAddCollector implements NodeCollectorInterface
$this->nodesToAddAfter[$position][] = $this->wrapToExpression($addedNode);
}
/**
* @return Stmt[]
*/
public function getNodesToAddAfterNode(Node $node): array
{
$position = spl_object_hash($node);
return $this->nodesToAddAfter[$position] ?? [];
}
/**
* @return Stmt[]
*/
public function getNodesToAddBeforeNode(Node $node): array
{
$position = spl_object_hash($node);

View File

@ -79,7 +79,7 @@ final class NodesToRemoveCollector implements NodeCollectorInterface
}
/**
* @return Node[]|Stmt[]
* @return Node[]
*/
public function getNodesToRemove(): array
{

View File

@ -71,6 +71,7 @@ final class PropertyToAddCollector implements NodeCollectorInterface
/**
* @var ClassConst[]
* @return ClassConst[]
*/
public function getConstantsByClass(Class_ $class): array
{
@ -79,7 +80,7 @@ final class PropertyToAddCollector implements NodeCollectorInterface
}
/**
* @var Type[]|null[]
* @return Type[]|null[]
*/
public function getPropertiesByClass(Class_ $class): array
{
@ -88,7 +89,7 @@ final class PropertyToAddCollector implements NodeCollectorInterface
}
/**
* @var Type[]|null[]
* @return Type[]|null[]
*/
public function getPropertiesWithoutConstructorByClass(Class_ $class): array
{

View File

@ -37,7 +37,7 @@ final class NodeAddingPostRector extends AbstractPostRector
}
/**
* @return Node[]|Node|null
* @return mixed[]|Node
*/
public function leaveNode(Node $node)
{

View File

@ -74,7 +74,7 @@ final class NodeRemovingRector extends AbstractPostRector
}
/**
* @return int|Node|Node[]|null
* @return int|Node
*/
public function leaveNode(Node $node)
{

View File

@ -105,7 +105,9 @@ final class CreateCommand extends Command
{
$rectorRecipe = $this->parameterProvider->provideParameter(Option::RECTOR_RECIPE);
$configuration = $this->configurationFactory->createFromRectorRecipe($rectorRecipe);
$isRectorRepository = $this->isRectorRepository();
$configuration = $this->configurationFactory->createFromRectorRecipe($rectorRecipe, $isRectorRepository);
$templateVariables = $this->templateVariablesFactory->createFromConfiguration($configuration);
// setup psr-4 autoload, if not already in
@ -118,7 +120,7 @@ final class CreateCommand extends Command
$isUnwantedOverride = $this->overrideGuard->isUnwantedOverride(
$templateFileInfos,
$templateVariables,
$configuration->getPackage(),
$configuration,
$targetDirectory
);
if ($isUnwantedOverride) {
@ -143,6 +145,11 @@ final class CreateCommand extends Command
return ShellCode::SUCCESS;
}
private function isRectorRepository(): bool
{
return file_exists(__DIR__ . '/../../../../vendor');
}
/**
* @param string[] $generatedFilePaths
*/

View File

@ -17,6 +17,11 @@ final class ComposerPackageAutoloadUpdater
*/
private const PSR_4 = 'psr-4';
/**
* @var string
*/
private const AUTOLOAD_DEV = 'autoload-dev';
/**
* @var JsonFileSystem
*/
@ -55,8 +60,10 @@ final class ComposerPackageAutoloadUpdater
return;
}
$composerJson['autoload'][self::PSR_4][$package->getSrcNamespace()] = $package->getSrcDirectory();
$composerJson['autoload-dev'][self::PSR_4][$package->getTestsNamespace()] = $package->getTestsDirectory();
$srcAutoload = $configuration->isRectorRepository() ? 'autoload' : self::AUTOLOAD_DEV;
$composerJson[$srcAutoload][self::PSR_4][$package->getSrcNamespace()] = $package->getSrcDirectory();
$composerJson[self::AUTOLOAD_DEV][self::PSR_4][$package->getTestsNamespace()] = $package->getTestsDirectory();
$this->jsonFileSystem->saveJsonToFile($composerJsonFilePath, $composerJson);
@ -65,7 +72,7 @@ final class ComposerPackageAutoloadUpdater
private function resolvePackage(Configuration $configuration): Package
{
if ($configuration->getPackage() === Package::UTILS) {
if (! $configuration->isRectorRepository()) {
return new Package(
'Utils\\Rector\\',
'Utils\\Rector\\Tests\\',
@ -84,7 +91,13 @@ final class ComposerPackageAutoloadUpdater
private function isPackageAlreadyLoaded(array $composerJson, Package $package): bool
{
return isset($composerJson['autoload'][self::PSR_4][$package->getSrcNamespace()]);
foreach (['autoload', self::AUTOLOAD_DEV] as $autoloadSection) {
if (isset($composerJson[$autoloadSection][self::PSR_4][$package->getSrcNamespace()])) {
return true;
}
}
return false;
}
private function rebuildAutoload(): void

View File

@ -32,7 +32,7 @@ final class ConfigurationFactory
/**
* @param mixed[] $rectorRecipe
*/
public function createFromRectorRecipe(array $rectorRecipe): Configuration
public function createFromRectorRecipe(array $rectorRecipe, bool $isRectorRepository): Configuration
{
$this->recipeGuard->ensureRecipeIsValid($rectorRecipe);
@ -55,7 +55,8 @@ final class ConfigurationFactory
(array) $rectorRecipe[RecipeOption::RULE_CONFIGURATION],
array_filter((array) $rectorRecipe[RecipeOption::SOURCE]),
$set,
$this->isPhpSnippet($rectorRecipe[RecipeOption::CODE_BEFORE])
$this->isPhpSnippet($rectorRecipe[RecipeOption::CODE_BEFORE]),
$isRectorRepository
);
}

View File

@ -7,6 +7,7 @@ namespace Rector\RectorGenerator\FileSystem;
use Nette\Utils\Strings;
use Rector\Core\Testing\PHPUnit\StaticPHPUnitEnvironment;
use Rector\RectorGenerator\Finder\TemplateFinder;
use Rector\RectorGenerator\ValueObject\Configuration;
use Rector\RectorGenerator\ValueObject\Package;
use Symplify\SmartFileSystem\SmartFileInfo;
@ -18,13 +19,13 @@ final class TemplateFileSystem
public function resolveDestination(
SmartFileInfo $smartFileInfo,
array $templateVariables,
string $package,
Configuration $configuration,
string $targetDirectory
): string {
$destination = $smartFileInfo->getRelativeFilePathFromDirectory(TemplateFinder::TEMPLATES_DIRECTORY);
// normalize core package
if ($package === Package::UTILS) {
if (! $configuration->isRectorRepository()) {
// special keyword for 3rd party Rectors, not for core Github contribution
$destination = Strings::replace($destination, '#packages\/__Package__#', 'utils/rector');
}

View File

@ -53,7 +53,7 @@ final class FileGenerator
$generatedFilePaths[] = $this->generateFileInfoWithTemplateVariables(
$fileInfo,
$templateVariables,
$configuration->getPackage(),
$configuration,
$destinationDirectory
);
}
@ -64,13 +64,13 @@ final class FileGenerator
private function generateFileInfoWithTemplateVariables(
SmartFileInfo $smartFileInfo,
array $templateVariables,
string $package,
Configuration $configuration,
string $targetDirectory
): string {
$targetFilePath = $this->templateFileSystem->resolveDestination(
$smartFileInfo,
$templateVariables,
$package,
$configuration,
$targetDirectory
);

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Rector\RectorGenerator\Guard;
use Rector\RectorGenerator\FileSystem\TemplateFileSystem;
use Rector\RectorGenerator\ValueObject\Configuration;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\SmartFileSystem\SmartFileInfo;
@ -32,11 +33,16 @@ final class OverrideGuard
public function isUnwantedOverride(
array $templateFileInfos,
array $templateVariables,
string $package,
Configuration $configuration,
string $targetDirectory
): bool {
foreach ($templateFileInfos as $templateFileInfo) {
if (! $this->doesFileInfoAlreadyExist($templateVariables, $package, $templateFileInfo, $targetDirectory)) {
if (! $this->doesFileInfoAlreadyExist(
$templateVariables,
$configuration,
$templateFileInfo,
$targetDirectory
)) {
continue;
}
@ -48,14 +54,14 @@ final class OverrideGuard
private function doesFileInfoAlreadyExist(
array $templateVariables,
string $package,
Configuration $configuration,
SmartFileInfo $templateFileInfo,
string $targetDirectory
): bool {
$destination = $this->templateFileSystem->resolveDestination(
$templateFileInfo,
$templateVariables,
$package,
$configuration,
$targetDirectory
);

View File

@ -18,6 +18,11 @@ final class Configuration
*/
private $package;
/**
* @var bool
*/
private $isRectorRepository = false;
/**
* @var string
*/
@ -95,7 +100,8 @@ final class Configuration
array $ruleConfiguration,
array $source,
?Set $set,
bool $isPhpSnippet
bool $isPhpSnippet,
bool $isRectorRepository
) {
$this->package = $package;
$this->setName($name);
@ -110,6 +116,7 @@ final class Configuration
$this->extraFileContent = $extraFileContent;
$this->extraFileName = $extraFileName;
$this->ruleConfiguration = $ruleConfiguration;
$this->isRectorRepository = $isRectorRepository;
}
public function getDescription(): string
@ -119,11 +126,19 @@ final class Configuration
public function getPackage(): string
{
if (! $this->isRectorRepository) {
return 'Utils';
}
return $this->package;
}
public function getPackageDirectory(): string
{
if (! $this->isRectorRepository) {
return 'rector';
}
// special cases
if ($this->package === 'PHPUnit') {
return 'phpunit';
@ -200,6 +215,11 @@ final class Configuration
return $this->ruleConfiguration;
}
public function isRectorRepository(): bool
{
return $this->isRectorRepository;
}
private function setName(string $name): void
{
if (! Strings::endsWith($name, 'Rector')) {

View File

@ -87,6 +87,6 @@ final class RectorGeneratorTest extends AbstractKernelTestCase
{
$rectorRecipe = StaticRectorRecipeFactory::createWithConfiguration();
return $this->configurationFactory->createFromRectorRecipe($rectorRecipe);
return $this->configurationFactory->createFromRectorRecipe($rectorRecipe, true);
}
}

View File

@ -705,11 +705,4 @@ final class SetList
* @var string
*/
public const UNWRAP_COMPAT = __DIR__ . '/../../../../config/set/unwrap-compat.php';
/**
* @experimental
* @api
* @var string
*/
public const REPOSITORY_AS_SERVICE = __DIR__ . '/../../../../config/set/repository-as-service.php';
}

View File

@ -28,10 +28,11 @@ parameters:
# see https://github.com/symplify/coding-standard
symplify:
max_cognitive_complexity: 9 # default: 8
# @todo update, to make classes smaller
# max_class_cognitive_complexity: 40 # default: 50
max_class_cognitive_complexity: 50
parent_classes:
- Rector
required_see_types:
- PHPStan\Rules\Rule
- Rector\Core\Rector\AbstractRector
@ -70,6 +71,10 @@ parameters:
- config
excludes_analyse:
# iterable types
- '#with no value type specified in iterable type array#'
- '#type specified in iterable type (array|iterable)#'
# phsptan bug
- utils/phpstan-extensions/src/Rule/PreventParentMethodVisibilityOverrideRule.php
- utils/phpstan-extensions/src/Rule/KeepRectorNamespaceForRectorRule.php
@ -90,6 +95,11 @@ parameters:
- '*/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/Just*ExceptionWithoutNamespace.php'
ignoreErrors:
# @todo remove
# iterable types
- '#with no value type specified in iterable type array#'
- '#type specified in iterable type (array|iterable)#'
# false positive
- '#PHPDoc tag \@param for parameter \$node with type float is incompatible with native type PhpParser\\Node#'
@ -118,7 +128,6 @@ parameters:
# known values
- '#Cannot access property \$value on PhpParser\\Node\\Expr\\ArrayItem\|null#'
- '#Method Rector\\Symfony\\Rector\\New_\\StringToArrayArgumentProcessRector::findPreviousNodeAssign\(\) should return PhpParser\\Node\\Expr\\Assign\|null but returns PhpParser\\Node\|null#'
# known values
- '#Strict comparison using === between PhpParser\\Node\\Expr and null will always evaluate to false#'
@ -179,9 +188,6 @@ parameters:
- '#Method Rector\\Doctrine\\Rector\\MethodCall\\ChangeSetIdToUuidValueRector\:\:getSetUuidMethodCallOnSameVariable\(\) should return PhpParser\\Node\\Expr\\MethodCall\|null but returns PhpParser\\Node\|null#'
# bugs
- '#Parameter \#1 \$items of class PhpParser\\Node\\Expr\\Array_ constructor expects array<PhpParser\\Node\\Expr\\ArrayItem\>, array<PhpParser\\Node\\Expr\\ArrayItem\|null\> given#'
# known value
- '#Method Rector\\StrictCodeQuality\\Rector\\Stmt\\VarInlineAnnotationToAssertRector\:\:findVariableByName\(\) should return PhpParser\\Node\\Expr\\Variable\|null but returns PhpParser\\Node\|null#'
@ -238,7 +244,6 @@ parameters:
- '#Parameter \#1 \$sprintfFuncCall of method Rector\\Core\\PhpParser\\NodeTransformer\:\:transformSprintfToArray\(\) expects PhpParser\\Node\\Expr\\FuncCall, PhpParser\\Node given#'
- '#Parameter \#1 \$nodes of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:find\(\) expects array<PhpParser\\Node\>\|PhpParser\\Node, array<PhpParser\\Node\\Stmt\>\|null given#'
- '#PHPDoc tag @return with type iterable<object\> is not subtype of native type array#'
- '#Method Rector\\SOLID\\Reflection\\ParentConstantReflectionResolver\:\:(.*?)\(\) should return ReflectionClassConstant\|null but returns ReflectionClassConstant\|false#'
- '#Parameter \#1 \$firstStmt of method Rector\\Generic\\Rector\\MethodBody\\NormalToFluentRector\:\:isBothMethodCallMatch\(\) expects PhpParser\\Node\\Stmt\\Expression, PhpParser\\Node\\Stmt given#'
- '#Method Rector\\Core\\Rector\\AbstractRector\:\:wrapToArg\(\) should return array<PhpParser\\Node\\Arg\> but returns array<PhpParser\\Node\\Arg\|PhpParser\\Node\\Expr\>#'
@ -287,10 +292,6 @@ parameters:
- *Test.php
- *TestCase.php
# iterable types
- '#with no value type specified in iterable type array#'
- '#type specified in iterable type (array|iterable)#'
-
message: "#^Cognitive complexity for \"Rector\\\\BetterPhpDocParser\\\\Printer\\\\WhitespaceDetector\\:\\:detectOldWhitespaces\\(\\)\" is 18, keep it under 9$#"
count: 1
@ -317,7 +318,6 @@ parameters:
- "#^Cognitive complexity for \"Rector\\\\Php70\\\\EregToPcreTransformer\\:\\:(.*?)\" is (.*?), keep it under 9$#"
- '#Use explicit return value over magic &reference#'
- '#Method Rector\\Order\\StmtOrder\:\:createOldToNewKeys\(\) should return array<int\> but returns array\|false#'
- '#In method "Rector\\Utils\\ProjectValidator\\Process\\ParallelTaskRunner\:\:(.*?)", caught "Throwable" must be rethrown\. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception#'
# weird
@ -327,25 +327,20 @@ parameters:
- '#Class cognitive complexity for "DumpNodesCommand" is \d+, keep it under 50#'
- '#Cognitive complexity for "Rector\\Utils\\DocumentationGenerator\\Command\\DumpNodesCommand\:\:execute\(\)" is \d+, keep it under 9#'
- '#Method Rector\\Utils\\DocumentationGenerator\\Node\\NodeClassProvider\:\:getNodeClasses\(\) should return array<class\-string\> but returns array<int, \(int\|string\)\>#'
- '#Parameter \#1 \$node of method Rector\\PostRector\\Collector\\NodesToAddCollector\:\:wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#'
- '#Access to an undefined property PhpParser\\Node\\Expr\:\:\$class#'
- '#Method Rector\\BetterPhpDocParser\\Tests\\PhpDocParser\\AbstractPhpDocInfoTest\:\:parseFileAndGetFirstNodeOfType\(\) should return PhpParser\\Node but returns PhpParser\\Node\|null#'
- '#Method Rector\\Core\\Testing\\Finder\\RectorsFinder\:\:findInDirectories\(\) should return array<Rector\\Core\\Contract\\Rector\\RectorInterface\> but returns array<object\>#'
- '#Property PhpParser\\Node\\Stmt\\Namespace_\:\:\$stmts \(array<PhpParser\\Node\\Stmt\>\) does not accept array<PhpParser\\Node\>#'
- '#Cognitive complexity for "Rector\\TypeDeclaration\\PHPStan\\Type\\ObjectTypeSpecifier\:\:matchShortenedObjectType\(\)" is 10, keep it under 9#'
- '#Parameter \#1 \$type of method PhpParser\\Builder\\FunctionLike\:\:setReturnType\(\) expects PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|string, PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType given#'
- '#Cognitive complexity for "Rector\\Core\\PhpParser\\Node\\Value\\ValueResolver\:\:getValue\(\)" is \d+, keep it under 9#'
- '#Cognitive complexity for "Rector\\NetteKdyby\\NodeResolver\\ListeningMethodsCollector\:\:collectFromClassAndGetSubscribedEventClassMethod\(\)" is 11, keep it under 9#'
- '#Cognitive complexity for "Rector\\NetteKdyby\\ContributeEventClassResolver\:\:resolveGetterMethodByEventClassAndParam\(\)" is \d+, keep it under 9#'
- '#Parameter \#1 \$type of class PhpParser\\Node\\NullableType constructor expects PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|string, PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType given#'
- '#Parameter \#1 \$object of function get_class expects object, PhpParser\\Node\|null given#'
- '#Class "Rector\\FileSystemRector\\Rector\\Removing\\RemoveProjectFileRector" is missing @see annotation with test case class reference#'
- '#Parameter \#1 \$type of method PhpParser\\Builder\\Param\:\:setType\(\) expects PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType\|string, PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType given#'
- '#Parameter \#1 \$node of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findFirstAncestorInstanceOf\(\) expects PhpParser\\Node, PhpParser\\Node\\Expr\\Variable\|null given#'
- '#Parameter \#1 \$expr of method Rector\\MagicDisclosure\\Matcher\\ClassNameTypeMatcher\:\:doesExprMatchNames\(\) expects PhpParser\\Node\\Expr, PhpParser\\Node\\Expr\|null given#'
- '#Parameter \#1 \$objectType of method Rector\\Naming\\Naming\\PropertyNaming\:\:fqnToVariableName\(\) expects PHPStan\\Type\\ObjectType\|string, PHPStan\\Type\\Type given#'
- '#Method Rector\\Core\\PhpParser\\Node\\NodeFactory\:\:createConcat\(\) should return PhpParser\\Node\\Expr\\BinaryOp\\Concat\|null but returns PhpParser\\Node\\Expr#'
- '#Method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findFirstNonAnonymousClass\(\) should return PhpParser\\Node\\Stmt\\Class_\|null but returns PhpParser\\Node\|null#'
@ -366,7 +361,6 @@ parameters:
- '#Call to an undefined method PhpParser\\Node\\Expr\\Error\|PhpParser\\Node\\Identifier\:\:toString\(\)#'
- '#Class Rector\\Renaming\\Tests\\Rector\\MethodCall\\RenameMethodRector\\Fixture\\SkipSelfMethodRename not found#'
# fixed in symplfiy dev
-
message: '#Separate function "Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ref\(\)" in method call to standalone row to improve readability#'
@ -381,12 +375,21 @@ parameters:
- '#Cognitive complexity for "Rector\\DeadCode\\NodeManipulator\\LivingCodeManipulator\:\:keepLivingCodeFromExpr\(\)" is \d+, keep it under 9#'
- '#Class with base "LexerFactory" name is already used in "PHPStan\\Parser\\LexerFactory", "Rector\\Core\\PhpParser\\Parser\\LexerFactory"\. Use unique name to make classes easy to recognize#'
- '#Parameter \#1 \$files of method Symplify\\SmartFileSystem\\Finder\\FinderSanitizer\:\:sanitize\(\) expects \(iterable<SplFileInfo\|string\>&Nette\\Utils\\Finder\)\|Symfony\\Component\\Finder\\Finder, array<string\> given#'
- '#Method Rector\\Core\\PhpParser\\Node\\Manipulator\\ChainMethodCallManipulator\:\:resolveRootMethodCall\(\) should return PhpParser\\Node\\Expr\\MethodCall\|null but returns PhpParser\\Node\|null#'
- '#Static property Symplify\\PackageBuilder\\Tests\\AbstractKernelTestCase\:\:\$container \(Psr\\Container\\ContainerInterface\) does not accept Rector\\Naming\\Tests\\Rector\\Class_\\RenamePropertyToMatchTypeRector\\Source\\ContainerInterface\|Symfony\\Component\\DependencyInjection\\Container#'
- '#Static property Rector\\Core\\Testing\\PHPUnit\\AbstractGenericRectorTestCase\:\:\$allRectorContainer \(Rector\\Naming\\Tests\\Rector\\Class_\\RenamePropertyToMatchTypeRector\\Source\\ContainerInterface\|Symfony\\Component\\DependencyInjection\\Container\|null\) does not accept Psr\\Container\\ContainerInterface#'
- '#Separate function "Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ref\(\)" in method call to standalone row to improve readability#'
- '#Class with base "(.*?)" name is already used in "_HumbugBox(.*?)#'
- '#Class Rector\\MagicDisclosure\\Tests\\Rector\\ClassMethod\\ReturnThisRemoveRector\\FixtureConfiguration\\SomeClass not found#'
# stubs
- '#Class Nette\\DI\\CompilerExtension not found#'
- '#Class Latte\\Macros\\MacroSet not found#'
- '#Static property Symplify\\PackageBuilder\\Tests\\AbstractKernelTestCase\:\:\$container \(Psr\\Container\\ContainerInterface\) does not accept Rector\\Naming\\Tests\\Rector\\Class_\\RenamePropertyToMatchTypeRector\\Source\\ContainerInterface\|Symfony\\Component\\DependencyInjection\\Container#'
# wtf
-
message: '#Else branch is unreachable because ternary operator condition is always true#'
path: 'rules/psr4/src/Composer/PSR4NamespaceMatcher.php'
# false positive
- '#Empty array passed to foreach#'
- '#Parameter \#1 \$arrayItem of method Rector\\NetteKdyby\\NodeResolver\\ListeningMethodsCollector\:\:resolveCustomClassMethodAndEventClass\(\) expects PhpParser\\Node\\Expr\\ArrayItem, PhpParser\\Node given#'
- '#Method Rector\\CodeQuality\\Rector\\Class_\\CompleteDynamicPropertiesRector\:\:resolvePropertiesToComplete\(\) should return array<int, PhpParser\\Node\\Stmt\\Property\> but returns array<int, \(int\|string\)\>#'
- '#Parameter \#1 \$type of method Rector\\NodeCollector\\NodeCollector\\ParsedNodeCollector<TNodeType of PhpParser\\Node\>\:\:getNodesByType\(\) expects class\-string<TNodeType of PhpParser\\Node\>, string given#'

View File

@ -4,14 +4,23 @@ declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Rector\TypeDeclaration\Rector\ClassMethod\AddArrayParamDocTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
// @todo make part of Rector CI
// add array-types
$services->set(AddArrayParamDocTypeRector::class);
$services->set(AddArrayReturnDocTypeRector::class);
$containerConfigurator->import(__DIR__ . '/create-rector.php', null, 'not_found');
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
$parameters->set(Option::SETS, [SetList::NAMING, SetList::REPOSITORY_AS_SERVICE]);
$parameters->set(Option::SETS, [SetList::NAMING]);
$parameters->set(Option::PATHS, [
__DIR__ . '/src',
__DIR__ . '/tests',

View File

@ -32,6 +32,9 @@ final class DoctrineRepositoryAsServiceTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return mixed[][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -72,6 +72,9 @@ final class MutualRenameTest extends AbstractFileSystemRectorTestCase
];
}
/**
* @return string[][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -47,6 +47,9 @@ final class MoveValueObjectsToValueObjectDirectoryRectorTest extends AbstractFil
];
}
/**
* @return array<string, mixed[]>
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -12,5 +12,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
->public();
$services->load('Rector\CakePHP\\', __DIR__ . '/../src')
->exclude([__DIR__ . '/../src/Rector/*']);
->exclude([__DIR__ . '/../src/Rector', __DIR__ . '/../src/ValueObject']);
};

View File

@ -9,6 +9,7 @@ use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use Rector\CakePHP\ValueObject\ArrayItemsAndFluentClass;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
@ -163,21 +164,21 @@ PHP
return null;
}
[$arrayItems, $fluentCalls] = $this->extractFluentMethods($argumentValue->items, $fluentMethods);
$arrayItemsAndFluentClass = $this->extractFluentMethods($argumentValue->items, $fluentMethods);
if ($arrayItems) {
$argumentValue->items = $arrayItems;
if ($arrayItemsAndFluentClass->getArrayItems() !== []) {
$argumentValue->items = $arrayItemsAndFluentClass->getArrayItems();
} else {
unset($methodCall->args[$argumentPosition - 1]);
}
if (! $fluentCalls) {
if ($arrayItemsAndFluentClass->getFluentCalls() === []) {
return null;
}
$node = $methodCall;
foreach ($fluentCalls as $method => $arg) {
foreach ($arrayItemsAndFluentClass->getFluentCalls() as $method => $arg) {
$args = $this->createArgs([$arg]);
$node = $this->createMethodCall($node, $method, $args);
}
@ -186,10 +187,10 @@ PHP
}
/**
* @param (ArrayItem|null)[] $originalArrayItems
* @param array<ArrayItem|null> $originalArrayItems
* @param string[] $arrayMap
*/
private function extractFluentMethods(array $originalArrayItems, array $arrayMap): array
private function extractFluentMethods(array $originalArrayItems, array $arrayMap): ArrayItemsAndFluentClass
{
$newArrayItems = [];
$fluentCalls = [];
@ -199,15 +200,18 @@ PHP
continue;
}
/** @var ArrayItem $arrayItem */
$key = $arrayItem->key;
if ($key instanceof String_ && isset($arrayMap[$key->value])) {
$fluentCalls[$arrayMap[$key->value]] = $arrayItem->value;
/** @var string $methodName */
$methodName = $arrayMap[$key->value];
$fluentCalls[$methodName] = $arrayItem->value;
} else {
$newArrayItems[] = $arrayItem;
}
}
return [$newArrayItems, $fluentCalls];
return new ArrayItemsAndFluentClass($newArrayItems, $fluentCalls);
}
}

View File

@ -47,6 +47,9 @@ PHP
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Property::class];

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Rector\CakePHP\ValueObject;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayItem;
final class ArrayItemsAndFluentClass
{
/**
* @var ArrayItem[]
*/
private $arrayItems = [];
/**
* @var array<string, Expr>
*/
private $fluentCalls = [];
/**
* @param ArrayItem[] $arrayItems
* @param array<string, Expr> $fluentCalls
*/
public function __construct(array $arrayItems, array $fluentCalls)
{
$this->arrayItems = $arrayItems;
$this->fluentCalls = $fluentCalls;
}
/**
* @return ArrayItem[]
*/
public function getArrayItems(): array
{
return $this->arrayItems;
}
/**
* @return array<string, Expr>
*/
public function getFluentCalls(): array
{
return $this->fluentCalls;
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Rector\CakePHP\Tests\Rector\MethodCall\RenameMethodCallBasedOnParameterRector;
use Iterator;
use Rector\CakePHP\Rector\MethodCall\RenameMethodCallBasedOnParameterRector;
use Rector\CakePHP\Tests\Rector\MethodCall\RenameMethodCallBasedOnParameterRector\Source\SomeModelType;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
@ -20,7 +21,7 @@ final class RenameMethodCallBasedOnParameterRectorTest extends AbstractRectorTes
}
/**
* @return string[]
* @return Iterator
*/
public function provideData(): iterable
{

View File

@ -113,6 +113,7 @@ PHP
// remove other properties that are accessible from this scope
/** @var string $class */
$class = $this->getName($node);
foreach ($propertiesToComplete as $key => $propertyToComplete) {
/** @var string $propertyToComplete */
if (! property_exists($class, $propertyToComplete)) {
@ -130,44 +131,11 @@ PHP
}
/**
* @return Type[]
* @return array<string, Type>
*/
private function resolveFetchedLocalPropertyNameToType(Class_ $class): array
{
$fetchedLocalPropertyNameToTypes = [];
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use (
&$fetchedLocalPropertyNameToTypes
): ?int {
// skip anonymous class scope
if ($this->isAnonymousClass($node)) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
if (! $node instanceof PropertyFetch) {
return null;
}
if (! $this->isVariableName($node->var, 'this')) {
return null;
}
// special Laravel collection scope
if ($this->shouldSkipForLaravelCollection($node)) {
return null;
}
$propertyName = $this->getName($node->name);
if ($propertyName === null) {
return null;
}
$propertyFetchType = $this->resolvePropertyFetchType($node);
$fetchedLocalPropertyNameToTypes[$propertyName][] = $propertyFetchType;
return null;
});
$fetchedLocalPropertyNameToTypes = $this->resolveFetchedLocalPropertyNamesToTypes($class);
// normalize types to union
$fetchedLocalPropertyNameToType = [];
@ -179,13 +147,14 @@ PHP
}
/**
* @param Type[] $fetchedLocalPropertyNameToTypes
* @return string[]
* @param array<string, Type> $fetchedLocalPropertyNameToTypes
* @return array<int, string>
*/
private function resolvePropertiesToComplete(Class_ $class, array $fetchedLocalPropertyNameToTypes): array
{
$propertyNames = $this->getClassPropertyNames($class);
/** @var string[] $fetchedLocalPropertyNames */
$fetchedLocalPropertyNames = array_keys($fetchedLocalPropertyNameToTypes);
return array_diff($fetchedLocalPropertyNames, $propertyNames);
@ -228,6 +197,63 @@ PHP
return $newProperties;
}
/**
* @return array<string, Type[]>
*/
private function resolveFetchedLocalPropertyNamesToTypes(Class_ $class): array
{
$fetchedLocalPropertyNameToTypes = [];
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use (
&$fetchedLocalPropertyNameToTypes
): ?int {
// skip anonymous class scope
if ($this->isAnonymousClass($node)) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
if (! $node instanceof PropertyFetch) {
return null;
}
if (! $this->isVariableName($node->var, 'this')) {
return null;
}
// special Laravel collection scope
if ($this->shouldSkipForLaravelCollection($node)) {
return null;
}
$propertyName = $this->getName($node->name);
if ($propertyName === null) {
return null;
}
$propertyFetchType = $this->resolvePropertyFetchType($node);
$fetchedLocalPropertyNameToTypes[$propertyName][] = $propertyFetchType;
return null;
});
return $fetchedLocalPropertyNameToTypes;
}
/**
* @return string[]
*/
private function getClassPropertyNames(Class_ $class): array
{
$propertyNames = [];
foreach ($class->getProperties() as $property) {
$propertyNames[] = $this->getName($property);
}
return $propertyNames;
}
private function shouldSkipForLaravelCollection(Node $node): bool
{
$staticCallOrClassMethod = $this->betterNodeFinder->findFirstAncestorInstancesOf(
@ -253,18 +279,4 @@ PHP
return new MixedType();
}
/**
* @return string[]
*/
private function getClassPropertyNames(Class_ $class): array
{
$propertyNames = [];
foreach ($class->getProperties() as $property) {
$propertyNames[] = $this->getName($property);
}
return $propertyNames;
}
}

View File

@ -30,7 +30,7 @@ final class UseImportsAdder
* @param Stmt[] $stmts
* @param FullyQualifiedObjectType[] $useImportTypes
* @param FullyQualifiedObjectType[] $functionUseImportTypes
* @return Stmt[]
* @return \PhpParser\Node\Stmt[]
*/
public function addImportsToStmts(array $stmts, array $useImportTypes, array $functionUseImportTypes): array
{

View File

@ -7,6 +7,7 @@ namespace Rector\CodingStyle\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Scalar\String_;
use Rector\CodingStyle\ValueObject\ConcatStringAndPlaceholders;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class ConcatJoiner
@ -24,10 +25,8 @@ final class ConcatJoiner
/**
* Joins all String_ nodes to string.
* Returns that string + array of non-string nodes that were replaced by hash placeholders
*
* @return string[]|Expr[][]
*/
public function joinToStringAndPlaceholderNodes(Concat $concat): array
public function joinToStringAndPlaceholderNodes(Concat $concat): ConcatStringAndPlaceholders
{
$parentNode = $concat->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof Concat) {
@ -37,7 +36,7 @@ final class ConcatJoiner
$this->processConcatSide($concat->left);
$this->processConcatSide($concat->right);
return [$this->content, $this->placeholderNodes];
return new ConcatStringAndPlaceholders($this->content, $this->placeholderNodes);
}
private function reset(): void

View File

@ -27,7 +27,7 @@ final class UseNameAliasToNameResolver
}
/**
* @return string[][]
* @return array<string, string[]>
*/
public function resolve(Use_ $use): array
{
@ -35,6 +35,10 @@ final class UseNameAliasToNameResolver
$shortNames = $this->shortNameResolver->resolveForNode($use);
foreach ($shortNames as $alias => $useImport) {
if (! is_string($alias)) {
continue;
}
$shortName = $this->classNaming->getShortName($useImport);
if ($shortName === $alias) {
continue;

View File

@ -49,6 +49,9 @@ CODE_SAMPLE
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class, MethodCall::class, StaticCall::class];

View File

@ -202,8 +202,10 @@ PHP
{
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo !== null) {
$phpDocInfo->removeByType(ReturnTagValueNode::class);
if ($phpDocInfo === null) {
return;
}
$phpDocInfo->removeByType(ReturnTagValueNode::class);
}
}

View File

@ -27,6 +27,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app
*
* @see \Rector\CodingStyle\Tests\Rector\String_\ManualJsonStringToJsonEncodeArrayRector\ManualJsonStringToJsonEncodeArrayRectorTest
*/
final class ManualJsonStringToJsonEncodeArrayRector extends AbstractRector
@ -121,15 +122,17 @@ PHP
return null;
}
/** @var Expr[] $placeholderNodes */
[$stringValue, $placeholderNodes] = $this->concatJoiner->joinToStringAndPlaceholderNodes($node->expr);
$concatStringAndPlaceholders = $this->concatJoiner->joinToStringAndPlaceholderNodes($node->expr);
// B. just start of a json? join with all the strings that concat so same variable
$concatExpressionJoinData = $this->collectContentAndPlaceholderNodesFromNextExpressions($node);
$placeholderNodes = array_merge($placeholderNodes, $concatExpressionJoinData->getPlaceholdersToNodes());
$placeholderNodes = array_merge(
$concatStringAndPlaceholders->getPlaceholderNodes(),
$concatExpressionJoinData->getPlaceholdersToNodes()
);
/** @var string $stringValue */
$stringValue = $concatStringAndPlaceholders->getContent();
$stringValue .= $concatExpressionJoinData->getString();
return $this->removeNodesAndCreateJsonEncodeFromStringValue(
@ -176,12 +179,12 @@ PHP
if ($valueNode instanceof String_) {
$concatExpressionJoinData->addString($valueNode->value);
} elseif ($valueNode instanceof Concat) {
/** @var Expr[] $newPlaceholderNodes */
[$content, $newPlaceholderNodes] = $this->concatJoiner->joinToStringAndPlaceholderNodes($valueNode);
/** @var string $content */
$joinToStringAndPlaceholderNodes = $this->concatJoiner->joinToStringAndPlaceholderNodes($valueNode);
$content = $joinToStringAndPlaceholderNodes->getContent();
$concatExpressionJoinData->addString($content);
foreach ($newPlaceholderNodes as $placeholder => $expr) {
foreach ($joinToStringAndPlaceholderNodes->getPlaceholderNodes() as $placeholder => $expr) {
/** @var string $placeholder */
$concatExpressionJoinData->addPlaceholderToNode($placeholder, $expr);
}

View File

@ -6,7 +6,6 @@ namespace Rector\CodingStyle\Rector\String_;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
@ -65,7 +64,7 @@ PHP
}
/**
* @return string[]
* @return mixed[]
*/
public function getExistingClasses(String_ $string): array
{
@ -77,6 +76,9 @@ PHP
});
}
/**
* @return mixed[]
*/
public function getParts(String_ $string, array $classNames): array
{
$classNames = array_map(function (string $className) {
@ -93,7 +95,7 @@ PHP
/**
* @param string[] $parts
* @return Expr[]
* @return ClassConstFetch[]|\PhpParser\Node\Scalar\String_[]
*/
private function createExpressionsToConcat(array $parts): array
{

View File

@ -236,6 +236,9 @@ PHP
return $this->extractMethodReturns($thrownClass, $methodName);
}
/**
* @return class-string[]
*/
private function identifyThrownThrowablesInMethodCall(MethodCall $methodCall): array
{
$fullyQualified = $this->classResolver->getClassFromMethodCall($methodCall);

View File

@ -35,7 +35,7 @@ final class RemoveUnusedAliasRector extends AbstractRector
private $resolvedNodeNames = [];
/**
* @var string[][]
* @var array<string, string[]>
*/
private $useNamesAliasToName = [];

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\ValueObject;
final class ConcatStringAndPlaceholders
{
/**
* @var string
*/
private $content;
/**
* @var array
*/
private $placeholderNodes = [];
public function __construct(string $content, array $placeholderNodes)
{
$this->content = $content;
$this->placeholderNodes = $placeholderNodes;
}
public function getContent(): string
{
return $this->content;
}
public function getPlaceholderNodes(): array
{
return $this->placeholderNodes;
}
}

View File

@ -24,6 +24,9 @@ final class FunctionCallToConstantRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return string[][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector;
use Iterator;
use Rector\Core\Configuration\Option;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Renaming\Rector\Class_\RenameClassRector;
@ -26,6 +27,9 @@ final class ImportRootNamespaceClassesDisabledTest extends AbstractRectorTestCas
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator
*/
public function provideData(): iterable
{
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureRoot');

View File

@ -121,6 +121,9 @@ final class LivingCodeManipulator
);
}
/**
* @return \PhpParser\Node\Expr[]
*/
private function processBinary(BinaryOp $binaryOp): array
{
return array_merge(
@ -129,6 +132,9 @@ final class LivingCodeManipulator
);
}
/**
* @return mixed[]
*/
private function processIsset(Isset_ $isset): array
{
return array_merge(...array_map(function (Expr $expr): array {

View File

@ -55,7 +55,7 @@ final class RemoveUnusedAssignVariableRector extends AbstractRector
}
/**
* @return class-string[]
* @return string[]
*/
public function getNodeTypes(): array
{

View File

@ -137,7 +137,7 @@ PHP
/**
* @param StaticCall|FuncCall|MethodCall $node
* @return Expr[]
* @return \PhpParser\Node\Expr[]|\PhpParser\Node[]
*/
private function resolveDefaultValuesFromCall(Node $node): array
{
@ -197,6 +197,7 @@ PHP
return [];
}
/** @var int[] $keysToRemove */
return $keysToRemove;
}
@ -213,7 +214,7 @@ PHP
}
/**
* @return Expr[]
* @return \PhpParser\Node[]|\PhpParser\Node\Expr[]
*/
private function resolveFuncCallDefaultParamValues(string $nodeName): array
{

View File

@ -79,7 +79,10 @@ final class UnusedClassResolver
$cachedUsedClassNames = $this->sortAndUniqueArray($cachedUsedClassNames);
return $this->cachedUsedClassNames = $cachedUsedClassNames;
/** @var string[] $cachedUsedClassNames */
$this->cachedUsedClassNames = $cachedUsedClassNames;
return $this->cachedUsedClassNames;
}
/**

View File

@ -40,7 +40,7 @@ final class UsedClassPropertyExtractor
/**
* @param ClassMethod[] $classMethods
* @return Property[]
* @return \PhpParser\Node\Stmt\Property[]
*/
public function extractFromClassMethods(array $classMethods, ?string $parentClassName = null): array
{

View File

@ -42,6 +42,9 @@ final class DecoupleClassMethodToOwnClassRectorTest extends AbstractRectorTestCa
];
}
/**
* @return string[][][][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -25,6 +25,9 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
*/
final class ChangeQuerySetParametersMethodParameterFromArrayToArrayCollectionRector extends AbstractRector
{
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];

View File

@ -51,6 +51,9 @@ final class ReportEntitiesWithAddedPropertiesEventSubscriber implements EventSub
);
}
/**
* @return string[]
*/
public static function getSubscribedEvents(): array
{
return [AfterProcessEvent::class => 'reportEntities'];

View File

@ -48,7 +48,7 @@ final class EntityWithMissingUuidProvider
}
/**
* @return Class_[]
* @return \PhpParser\Node\Stmt\Class_[]
*/
public function provide(): array
{
@ -76,7 +76,7 @@ final class EntityWithMissingUuidProvider
$this->entitiesWithMissingUuidProperty = $entitiesWithMissingUuidProperty;
return $entitiesWithMissingUuidProperty;
return $this->entitiesWithMissingUuidProperty;
}
private function hasClassIdPropertyWithUuidType(Class_ $class): bool

View File

@ -25,6 +25,9 @@ final class AddEntityIdByConditionRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return string[][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -74,7 +74,7 @@ final class CallTypeAnalyzer
/**
* @param MethodCall|StaticCall $node
* @return array<int, Type>
* @return \PHPStan\Type\Type[]
*/
private function getMethodParameterTypes(string $className, Node $node): array
{

View File

@ -200,6 +200,7 @@ PHP
/**
* @param Arg[] $argumentNodes
* @param mixed[] $before
* @return mixed[]
*/
private function resolveArgumentValuesToBeforeRecipe(array $argumentNodes, int $position, array $before): array
{

View File

@ -48,7 +48,7 @@ CODE_SAMPLE
}
/**
* @return class-string[]
* @return string[]
*/
public function getNodeTypes(): array
{

View File

@ -25,6 +25,9 @@ final class ChangeContractMethodSingleToManyRectorTest extends AbstractRectorTes
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return string[][][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -26,6 +26,9 @@ final class AddInterfaceByTraitRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return string[][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -28,6 +28,9 @@ final class RemoveFuncCallArgRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return int[][][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -28,6 +28,9 @@ final class RemoveIniGetSetFuncCallRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return string[][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -24,6 +24,9 @@ final class MethodCallToStaticCallRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return string[][][][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -25,6 +25,9 @@ final class SwapClassMethodArgumentsRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return int[][][][][]
*/
protected function getRectorsWithConfiguration(): array
{
return [

View File

@ -25,6 +25,9 @@ final class StaticCallToMethodCallRectorTest extends AbstractRectorTestCase
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
/**
* @return StaticCallToMethodCall[][][]
*/
protected function getRectorsWithConfiguration(): array
{
$configuration = [

View File

@ -60,6 +60,9 @@ PHP
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ArrayItem::class];
@ -137,7 +140,7 @@ PHP
}
/**
* @return Expr[]
* @return \PhpParser\Node\Scalar\String_[]|\PhpParser\Node\Expr[]|\PhpParser\Node\Expr\ClassConstFetch[]|FuncCall[]|MethodCall[]
*/
private function transformRulesSetToExpressionsArray(Expr $expr): array
{

View File

@ -6,6 +6,7 @@ namespace Rector\Legacy\Rector\FileSystem;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
@ -126,7 +127,7 @@ PHP
/**
* @param Node[] $nodes
* @return Node[]
* @return \PhpParser\Node[]|Stmt[]
*/
private function getFileOrNamespaceStmts(array $nodes): array
{
@ -167,7 +168,7 @@ PHP
/**
* @param Node[] $nodes
* @return Node[]
* @return \PhpParser\Node\Stmt\Namespace_[]|Class_[]
*/
private function resolveNodesToPrint(array $nodes, Class_ $class): array
{

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\MagicDisclosure\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
use Rector\NetteKdyby\Naming\VariableNaming;
@ -61,6 +62,7 @@ final class NonFluentChainMethodCallFactory
/**
* @param MethodCall[] $chainMethodCalls
* @return Expr[]|Return_[]
*/
public function createFromAssignObjectAndMethodCalls(
AssignAndRootExpr $assignAndRootExpr,
@ -100,7 +102,7 @@ final class NonFluentChainMethodCallFactory
/**
* @param MethodCall[] $chainMethodCalls
* @return Expr[]
* @return \PhpParser\Node\Expr\Assign[]|\PhpParser\Node\Expr\MethodCall[]
*/
private function createNonFluentMethodCalls(array $chainMethodCalls, AssignAndRootExpr $assignAndRootExpr): array
{

Some files were not shown because too many files have changed in this diff Show More