Remove dead classes (#1133)

This commit is contained in:
Tomas Votruba 2021-11-02 17:36:50 +01:00 committed by GitHub
parent 29b79786e2
commit b7d37b828e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 64 additions and 1060 deletions

View File

@ -34,9 +34,12 @@ jobs:
run: composer phpstan-config
-
name: Commented Code
name: 'Commented Code'
run: vendor/bin/easy-ci check-commented-code src packages rules tests packages-tests rules-tests --line-limit 5 --ansi
# -
# name: 'Active Classes'
# run: vendor/bin/easy-ci check-active-class src packages rules --ansi
# see https://github.com/rectorphp/rector-generator
-

View File

@ -26,10 +26,10 @@
"rector/rector-cakephp": "^0.11.6",
"rector/rector-doctrine": "^0.11.26",
"rector/rector-laravel": "^0.11.8",
"rector/rector-nette": "^0.11.31",
"rector/rector-nette": "^0.11.39",
"rector/rector-phpoffice": "^0.11.6",
"rector/rector-phpunit": "^0.11.16",
"rector/rector-symfony": "^0.11.31",
"rector/rector-symfony": "^0.11.33",
"sebastian/diff": "^4.0.4",
"ssch/typo3-rector": "^0.11.26",
"symfony/console": "^5.3.7",

48
easy-ci.php Normal file
View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\Core\Contract\PHPStan\Reflection\TypeToCallReflectionResolver\TypeToCallReflectionResolverInterface;
use Rector\Core\Contract\Processor\FileProcessorInterface;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\Php80\Contract\StrStartWithMatchAndRefactorInterface;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\ReadWrite\Contract\ReadNodeAnalyzerInterface;
use Rector\Set\Contract\SetListInterface;
use Rector\StaticTypeMapper\Contract\PhpDocParser\PhpDocTypeMapperInterface;
use Rector\StaticTypeMapper\Contract\PhpParser\PhpParserNodeMapperInterface;
use Rector\TypeDeclaration\Contract\TypeInferer\ParamTypeInfererInterface;
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\Contract\TypeInferer\ReturnTypeInfererInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\EasyCI\ValueObject\Option;
use Symplify\SimplePhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_SKIP, [
Command::class,
Application::class,
RectorInterface::class,
TypeToCallReflectionResolverInterface::class,
PropertyTypeInfererInterface::class,
ParamTypeInfererInterface::class,
ReturnTypeInfererInterface::class,
FileProcessorInterface::class,
ClassNameImportSkipVoterInterface::class,
StrStartWithMatchAndRefactorInterface::class,
PhpDocTypeMapperInterface::class,
PhpParserNodeMapperInterface::class,
TypeMapperInterface::class,
AbstractPhpDocNodeVisitor::class,
NodeNameResolverInterface::class,
NodeTypeResolverInterface::class,
ReadNodeAnalyzerInterface::class,
SetListInterface::class,
]);
};

View File

@ -50,6 +50,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
__DIR__ . '/utils',
__DIR__ . '/config',
__DIR__ . '/ecs.php',
__DIR__ . '/easy-ci.php',
__DIR__ . '/rector.php',
__DIR__ . '/scoper.php',
]);

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\ValueObject;
final class AroundSpaces
{
public function __construct(
private string $closingSpace,
private string $openingSpace
) {
}
public function getClosingSpace(): string
{
return $this->closingSpace;
}
public function getOpeningSpace(): string
{
return $this->openingSpace;
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\ValueObject\PhpDocNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use Rector\Core\Exception\ShouldNotHappenException;
use Stringable;
/**
* @deprecated
* Just for back compatibility
*/
abstract class AbstractTagValueNode implements Node, Stringable
{
use NodeAttributes;
public function __toString(): string
{
throw new ShouldNotHappenException('Implement in child class');
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\ValueObjectFactory\PhpDocNode\Symfony;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
final class SymfonyRouteTagValueNodeFactory
{
/**
* @param array<string, mixed> $items
*/
public function createFromItems(array $items): DoctrineAnnotationTagValueNode
{
return new DoctrineAnnotationTagValueNode(
new IdentifierTypeNode('Symfony\Component\Routing\Annotation\Route'),
null,
$items,
'path'
);
}
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\NodeTypeResolver\Exception;
use Exception;
final class MissingTagException extends Exception
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Testing\Contract;
interface ConfigFileAwareInterface
{
public function provideConfigFilePath(): string;
}

View File

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Testing\Contract;
use PhpParser\Node;
interface NodeTraversableInterface
{
/**
* @param Node[] $nodes
*/
public function traverseNodes(array $nodes): void;
}

View File

@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Testing\ValueObject;
use Rector\FileSystemRector\ValueObject\AddedFileWithContent;
use Symplify\SmartFileSystem\SmartFileInfo;
final class InputFilePathWithExpectedFile
{
public function __construct(
private string $inputFilePath,
private AddedFileWithContent $addedFileWithContent
) {
}
public function getInputFileInfo(): SmartFileInfo
{
return new SmartFileInfo($this->inputFilePath);
}
public function getAddedFileWithContent(): AddedFileWithContent
{
return $this->addedFileWithContent;
}
}

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\VendorLocker\Contract;
use PhpParser\Node;
interface NodeVendorLockerInterface
{
public function resolve(Node $node): bool;
}

View File

@ -1,79 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\VendorLocker\NodeVendorLocker;
use PhpParser\Node\Stmt\Property;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class PropertyVisibilityVendorLockResolver
{
public function __construct(
private NodeNameResolver $nodeNameResolver,
private FamilyRelationsAnalyzer $familyRelationsAnalyzer
) {
}
/**
* Checks for:
* - child classes required properties
*
* Prevents:
* - changing visibility conflicting with children
*/
public function isParentLockedProperty(Property $property): bool
{
$classReflection = $this->resolveClassReflection($property);
if (! $classReflection instanceof ClassReflection) {
return false;
}
$propertyName = $this->nodeNameResolver->getName($property);
foreach ($classReflection->getParents() as $parentClassReflection) {
if ($parentClassReflection->hasProperty($propertyName)) {
return true;
}
}
return false;
}
public function isChildLockedProperty(Property $property): bool
{
$classReflection = $this->resolveClassReflection($property);
if (! $classReflection instanceof ClassReflection) {
return false;
}
$propertyName = $this->nodeNameResolver->getName($property);
$childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection);
foreach ($childrenClassReflections as $childClassReflection) {
if ($childClassReflection === $classReflection) {
continue;
}
if ($childClassReflection->hasProperty($propertyName)) {
return true;
}
}
return false;
}
private function resolveClassReflection(Property $property): ?ClassReflection
{
$scope = $property->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
return null;
}
return $scope->getClassReflection();
}
}

View File

@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\DependencyInjection\NodeFactory;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\Type\ObjectType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\ValueObject\FrameworkName;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Symplify\Astral\ValueObject\NodeBuilder\MethodBuilder;
use Symplify\Astral\ValueObject\NodeBuilder\ParamBuilder;
final class InjectMethodFactory
{
public function __construct(
private ClassNaming $classNaming,
private NodeFactory $nodeFactory,
private PhpDocInfoFactory $phpDocInfoFactory,
private PropertyNaming $propertyNaming,
private TypeFactory $typeFactory
) {
}
/**
* @param ObjectType[] $objectTypes
*/
public function createFromTypes(array $objectTypes, string $className, string $framework): ClassMethod
{
$objectTypes = $this->typeFactory->uniquateTypes($objectTypes);
$shortClassName = $this->classNaming->getShortName($className);
$methodBuilder = new MethodBuilder('inject' . $shortClassName);
$methodBuilder->makePublic();
foreach ($objectTypes as $objectType) {
/** @var ObjectType $objectType */
$propertyName = $this->propertyNaming->fqnToVariableName($objectType);
$paramBuilder = new ParamBuilder($propertyName);
$paramBuilder->setType(new FullyQualified($objectType->getClassName()));
$methodBuilder->addParam($paramBuilder);
$assign = $this->nodeFactory->createPropertyAssignment($propertyName);
$methodBuilder->addStmt($assign);
}
$classMethod = $methodBuilder->getNode();
if ($framework === FrameworkName::SYMFONY) {
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
$phpDocInfo->addPhpDocTagNode(new PhpDocTagNode('@required', new GenericTagValueNode('')));
}
return $classMethod;
}
}

View File

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Naming\Naming;
use Nette\Utils\Strings;
use PhpParser\Node\Expr;
final class MethodNameResolver
{
public function __construct(
private VariableNaming $variableNaming
) {
}
public function resolveGetterFromReturnedExpr(Expr $expr): ?string
{
$variableName = $this->variableNaming->resolveFromNode($expr);
if ($variableName === null) {
return null;
}
return 'get' . ucfirst($variableName);
}
public function resolveIsserFromReturnedExpr(Expr $expr): ?string
{
$variableName = $this->variableNaming->resolveFromNode($expr);
if ($variableName === null) {
return null;
}
if (Strings::match($variableName, '#^(is)#')) {
return $variableName;
}
return 'is' . ucfirst($variableName);
}
}

View File

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Order\Contract;
interface RankeableInterface
{
public function getName(): string;
/**
* @return bool[]|int[]
*/
public function getRanks(): array;
}

View File

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Order\Order;
final class OrderChangeAnalyzer
{
/**
* @param array<int, int> $oldToNewKeys
*/
public function hasOrderChanged(array $oldToNewKeys): bool
{
$keys = array_keys($oldToNewKeys);
$values = array_values($oldToNewKeys);
return $keys !== $values;
}
}

View File

@ -1,134 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Order;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Trait_;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Order\Contract\RankeableInterface;
use Rector\Order\ValueObject\ClassConstRankeable;
use Rector\Order\ValueObject\ClassMethodRankeable;
use Rector\Order\ValueObject\PropertyRankeable;
final class StmtVisibilitySorter
{
public function __construct(
private NodeNameResolver $nodeNameResolver
) {
}
/**
* @return string[]
*/
public function sortProperties(Class_ | Trait_ $classLike): array
{
$propertyRankeables = [];
foreach ($classLike->stmts as $position => $propertyStmt) {
if (! $propertyStmt instanceof Property) {
continue;
}
/** @var string $propertyName */
$propertyName = $this->nodeNameResolver->getName($propertyStmt);
$propertyRankeables[] = new PropertyRankeable(
$propertyName,
$this->getVisibilityLevelOrder($propertyStmt),
$propertyStmt,
$position
);
}
return $this->sortByRanksAndGetNames($propertyRankeables);
}
/**
* @return string[]
*/
public function sortMethods(ClassLike $classLike): array
{
$classMethodsRankeables = [];
foreach ($classLike->stmts as $position => $classStmt) {
if (! $classStmt instanceof ClassMethod) {
continue;
}
/** @var string $classMethodName */
$classMethodName = $this->nodeNameResolver->getName($classStmt);
$classMethodsRankeables[] = new ClassMethodRankeable(
$classMethodName,
$this->getVisibilityLevelOrder($classStmt),
$position,
$classStmt
);
}
return $this->sortByRanksAndGetNames($classMethodsRankeables);
}
/**
* @return string[]
*/
public function sortConstants(Class_ | Interface_ $classLike): array
{
$classConstsRankeables = [];
foreach ($classLike->stmts as $position => $constantStmt) {
if (! $constantStmt instanceof ClassConst) {
continue;
}
/** @var string $constantName */
$constantName = $this->nodeNameResolver->getName($constantStmt);
$classConstsRankeables[] = new ClassConstRankeable(
$constantName,
$this->getVisibilityLevelOrder($constantStmt),
$position
);
}
return $this->sortByRanksAndGetNames($classConstsRankeables);
}
private function getVisibilityLevelOrder(ClassMethod | Property | ClassConst $stmt): int
{
if ($stmt->isPrivate()) {
return 2;
}
if ($stmt->isProtected()) {
return 1;
}
return 0;
}
/**
* @param RankeableInterface[] $rankeables
* @return string[]
*/
private function sortByRanksAndGetNames(array $rankeables): array
{
uasort(
$rankeables,
fn (RankeableInterface $firstRankeable, RankeableInterface $secondRankeable): int => $firstRankeable->getRanks() <=> $secondRankeable->getRanks()
);
$names = [];
foreach ($rankeables as $rankeable) {
$names[] = $rankeable->getName();
}
return $names;
}
}

View File

@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Order\ValueObject;
use Rector\Order\Contract\RankeableInterface;
final class ClassConstRankeable implements RankeableInterface
{
public function __construct(
private string $name,
private int $visibility,
private int $position
) {
}
public function getName(): string
{
return $this->name;
}
/**
* An array to sort the element order by
* @return int[]
*/
public function getRanks(): array
{
return [$this->visibility, $this->position];
}
}

View File

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Order\ValueObject;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Order\Contract\RankeableInterface;
final class ClassMethodRankeable implements RankeableInterface
{
public function __construct(
private string $name,
private int $visibility,
private int $position,
private ClassMethod $classMethod
) {
}
public function getName(): string
{
return $this->name;
}
/**
* An array to sort the element order by
* @return bool[]|int[]
*/
public function getRanks(): array
{
return [
$this->visibility,
$this->classMethod->isStatic(),
// negated on purpose, to put abstract later
! $this->classMethod->isAbstract(),
$this->classMethod->isFinal(),
$this->position,
];
}
}

View File

@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Order\ValueObject;
use PhpParser\Node\Stmt\Property;
use Rector\Order\Contract\RankeableInterface;
final class PropertyRankeable implements RankeableInterface
{
public function __construct(
private string $name,
private int $visibility,
private Property $property,
private int $position
) {
}
public function getName(): string
{
return $this->name;
}
/**
* @return bool[]|int[]
*/
public function getRanks(): array
{
return [$this->visibility, $this->property->isStatic(), $this->position];
}
}

View File

@ -1,43 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Privatization\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class EventSubscriberMethodNamesResolver
{
public function __construct(
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser
) {
}
/**
* @return string[]
*/
public function resolveFromClassMethod(ClassMethod $classMethod): array
{
$methodNames = [];
$this->simpleCallableNodeTraverser->traverseNodesWithCallable(
(array) $classMethod->stmts,
function (Node $node) use (&$methodNames) {
if (! $node instanceof ArrayItem) {
return null;
}
if (! $node->value instanceof String_) {
return null;
}
$methodNames[] = $node->value->value;
}
);
return $methodNames;
}
}

View File

@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\NodeFactory;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Symplify\Astral\ValueObject\NodeBuilder\MethodBuilder;
final class ClassMethodFactory
{
public function createClassMethodFromFunction(string $methodName, Function_ $function): ClassMethod
{
$methodBuilder = new MethodBuilder($methodName);
$methodBuilder->makePublic();
$methodBuilder->makeStatic();
$methodBuilder->addStmts($function->stmts);
return $methodBuilder->getNode();
}
}

View File

@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\NodeFactory;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\MagicConst\Dir;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\PhpParser\Node\NodeFactory;
final class ProvideConfigFilePathClassMethodFactory
{
public function __construct(
private NodeFactory $nodeFactory
) {
}
public function create(): ClassMethod
{
$classMethod = $this->nodeFactory->createPublicMethod('provideConfigFilePath');
$classMethod->returnType = new Identifier('string');
$concat = new Concat(new Dir(), new String_('/config/configured_rule.php'));
$return = new Return_($concat);
$classMethod->stmts[] = $return;
return $classMethod;
}
}

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\ValueObject;
final class FunctionToStaticCall
{
public function __construct(
private string $function,
private string $class,
private string $method
) {
}
public function getClass(): string
{
return $this->class;
}
public function getMethod(): string
{
return $this->method;
}
public function getFunction(): string
{
return $this->function;
}
}

View File

@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\TypeDeclaration\Enum;
use MyCLabs\Enum\Enum;
/**
* @enum
* @method static TypeStrictness STRICTNESS_TYPE_DECLARATION()
* @method static TypeStrictness STRICTNESS_DOCBLOCK()
*/
final class TypeStrictness extends Enum
{
/**
* @var string
*/
private const STRICTNESS_TYPE_DECLARATION = 'type_declaration';
/**
* @var string
*/
private const STRICTNESS_DOCBLOCK = 'docblock';
}

View File

@ -12,22 +12,6 @@ use Rector\Core\ValueObject\Bootstrap\BootstrapConfigs;
final class RectorContainerFactory
{
/**
* @param string[] $configFiles
* @api
*/
public function createFromConfigs(array $configFiles): ContainerInterface
{
// to override the configs without clearing cache
// $isDebug = StaticInputDetector::isDebug();
$phpStanStubLoader = new PHPStanStubLoader();
$phpStanStubLoader->loadStubs();
$rectorKernel = new RectorKernel();
return $rectorKernel->createFromConfigs($configFiles);
}
public function createFromBootstrapConfigs(BootstrapConfigs $bootstrapConfigs): ContainerInterface
{
$container = $this->createFromConfigs($bootstrapConfigs->getConfigFiles());
@ -43,7 +27,15 @@ final class RectorContainerFactory
}
/**
* @see https://symfony.com/doc/current/components/dependency_injection/compilation.html#dumping-the-configuration-for-performance
* @param string[] $configFiles
* @api
*/
private function createFromConfigs(array $configFiles): ContainerInterface
{
$phpStanStubLoader = new PHPStanStubLoader();
$phpStanStubLoader->loadStubs();
$rectorKernel = new RectorKernel();
return $rectorKernel->createFromConfigs($configFiles);
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Exception\Application;
use Exception;
use Symplify\SmartFileSystem\SmartFileInfo;
use Throwable;
final class FileProcessingException extends Exception
{
public function __construct(SmartFileInfo $smartFileInfo, Throwable $throwable)
{
$message = sprintf(
'Processing file "%s" failed. %s%s',
$smartFileInfo->getRealPath(),
PHP_EOL . PHP_EOL,
$throwable
);
parent::__construct($message);
}
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Exception;
use Exception;
final class InvalidNodeTypeException extends Exception
{
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Exception\Testing;
use Exception;
final class SuperfluousAfterContentFixtureException extends Exception
{
}

View File

@ -1,74 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\NodeFactory;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Namespace_;
use Symplify\Astral\ValueObject\NodeBuilder\ClassBuilder;
use Symplify\Astral\ValueObject\NodeBuilder\NamespaceBuilder;
use Symplify\Astral\ValueObject\NodeBuilder\PropertyBuilder;
use Symplify\Astral\ValueObject\NodeBuilder\TraitUseBuilder;
/**
* @see \Rector\Core\Tests\NodeFactory\ClassWithPublicPropertiesFactory\ClassWithPublicPropertiesFactoryTest
*/
final class ClassWithPublicPropertiesFactory
{
/**
* @param string $fullyQualifiedName fully qualified name of new class
* @param array<string, array{type: string, nullable?: bool}> $properties
* @param string|null $parent fully qualified name of parent class
* @param string[] $traits list of fully qualified names of traits used in class
*/
public function createNode(
string $fullyQualifiedName,
array $properties,
?string $parent = null,
array $traits = []
): Namespace_ | Class_ {
$namespaceParts = explode('\\', ltrim($fullyQualifiedName, '\\'));
$className = array_pop($namespaceParts);
$namespace = implode('\\', $namespaceParts);
$namespaceBuilder = null;
if ($namespace !== '') {
$namespaceBuilder = new NamespaceBuilder($namespace);
}
$classBuilder = new ClassBuilder($className);
if ($parent !== null && $parent !== '') {
$classBuilder->extend($this->fixFullyQualifiedName($parent));
}
foreach ($traits as $trait) {
$classBuilder->addStmt(new TraitUseBuilder($this->fixFullyQualifiedName($trait)));
}
foreach ($properties as $propertyName => $propertySettings) {
$propertyType = $propertySettings['type'];
$nullable = $propertySettings['nullable'] ?? false;
if ($nullable) {
$propertyType = new NullableType($propertyType);
}
$propertyBuilder = new PropertyBuilder($propertyName);
$propertyBuilder->setType($propertyType);
$classBuilder->addStmt($propertyBuilder);
}
if ($namespaceBuilder !== null) {
$namespaceBuilder->addStmt($classBuilder);
return $namespaceBuilder->getNode();
}
return $classBuilder->getNode();
}
private function fixFullyQualifiedName(string $fullyQualifiedName): string
{
return '\\' . ltrim($fullyQualifiedName, '\\');
}
}

View File

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\PhpParser\Parser;
use PhpParser\Lexer;
use PhpParser\Parser;
use PhpParser\ParserFactory;
final class NikicPhpParserFactory
{
public function __construct(
private ParserFactory $parserFactory,
private Lexer $lexer,
) {
}
public function create(): Parser
{
return $this->parserFactory->create(ParserFactory::PREFER_PHP7, $this->lexer, [
'useIdentifierNodes' => true,
'useConsistentVariableNodes' => true,
'useExpressionStatements' => true,
'useNopStatements' => false,
]);
}
}

View File

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Tests\NodeFactory\ClassWithPublicPropertiesFactory;
use Iterator;
use Nette\Utils\Json;
use Rector\Core\NodeFactory\ClassWithPublicPropertiesFactory;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\EasyTesting\DataProvider\StaticFixtureFinder;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see \Rector\Core\NodeFactory\ClassWithPublicPropertiesFactory
*/
final class ClassWithPublicPropertiesFactoryTest extends AbstractTestCase
{
private ClassWithPublicPropertiesFactory $classWithPublicPropertiesFactory;
private BetterStandardPrinter $betterStandardPrinter;
protected function setUp(): void
{
$this->bootFromConfigFiles([__DIR__ . '/../../../config/config.php']);
$this->classWithPublicPropertiesFactory = $this->getService(ClassWithPublicPropertiesFactory::class);
$this->betterStandardPrinter = $this->getService(BetterStandardPrinter::class);
}
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fixtureFileInfo): void
{
$contents = $fixtureFileInfo->getContents();
// normalize for windows compat
$contents = str_replace("\r\n", "\n", $contents);
[$content, $expected] = explode("-----\n", $contents, 2);
$classSettings = Json::decode($content, Json::FORCE_ARRAY);
$node = $this->classWithPublicPropertiesFactory->createNode(
$classSettings['fullyQualifiedName'],
$classSettings['properties'],
$classSettings['parent'] ?? null,
$classSettings['traits'] ?? []
);
$output = "<?php\n\n" . $this->betterStandardPrinter->print($node) . "\n";
$this->assertSame($expected, $output);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return StaticFixtureFinder::yieldDirectoryExclusively(__DIR__ . '/Fixture');
}
}

View File

@ -1,12 +0,0 @@
{
"fullyQualifiedName": "EmptyClassNoNamespace",
"properties": [],
"parent": null,
"traits": []
}
-----
<?php
class EmptyClassNoNamespace
{
}

View File

@ -1,31 +0,0 @@
{
"fullyQualifiedName": "\\MyNamespace\\MyClassName",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "int",
"nullable": true
}
},
"parent": "\\AnotherNamespace\\ParentClass",
"traits": [
"\\FooNamespace\\FirstTrait",
"\\BarNamespace\\SecondTrait",
"\\NoNamespaceThirdTrait"
]
}
-----
<?php
namespace MyNamespace;
class MyClassName extends \AnotherNamespace\ParentClass
{
use \FooNamespace\FirstTrait;
use \BarNamespace\SecondTrait;
use \NoNamespaceThirdTrait;
public string $foo;
public ?int $bar;
}

View File

@ -1,31 +0,0 @@
{
"fullyQualifiedName": "MyNamespace\\MyClassName",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "int",
"nullable": true
}
},
"parent": "AnotherNamespace\\ParentClass",
"traits": [
"FooNamespace\\FirstTrait",
"BarNamespace\\SecondTrait",
"NoNamespaceThirdTrait"
]
}
-----
<?php
namespace MyNamespace;
class MyClassName extends \AnotherNamespace\ParentClass
{
use \FooNamespace\FirstTrait;
use \BarNamespace\SecondTrait;
use \NoNamespaceThirdTrait;
public string $foo;
public ?int $bar;
}