Remove dead classes #2, remove unused PlatformAgnosticAssertions, remove ConsoleShowOutputFormatter (#1134)

* remove daed classes

* make show output format simple again, just CLI output as helper command

* move MethodCallManipulator to rector-nette

* cleanup
This commit is contained in:
Tomas Votruba 2021-11-02 20:48:59 +01:00 committed by GitHub
parent b7d37b828e
commit ff45ce65dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 39 additions and 723 deletions

View File

@ -37,9 +37,9 @@ jobs:
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
-
name: 'Active Classes'
run: vendor/bin/easy-ci check-active-class bin config src packages rules --ansi
# see https://github.com/rectorphp/rector-generator
-

View File

@ -2,18 +2,27 @@
declare(strict_types=1);
use PHPStan\PhpDocParser\Parser\TypeParser;
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\Core\Contract\PHPStan\Reflection\TypeToCallReflectionResolver\TypeToCallReflectionResolverInterface;
use Rector\Core\Contract\Processor\FileProcessorInterface;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\NodeManipulator\MethodCallManipulator;
use Rector\DependencyInjection\NodeManipulator\PropertyConstructorInjectionManipulator;
use Rector\FileFormatter\Contract\Formatter\FileFormatterInterface;
use Rector\Naming\Contract\Guard\ConflictingNameGuardInterface;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\NodeTypeResolver\DependencyInjection\PHPStanServicesFactory;
use Rector\NodeTypeResolver\Reflection\BetterReflection\RectorBetterReflectionSourceLocatorFactory;
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\Testing\PHPUnit\AbstractTestCase;
use Rector\TypeDeclaration\Contract\TypeInferer\ParamTypeInfererInterface;
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
use Rector\TypeDeclaration\Contract\TypeInferer\ReturnTypeInfererInterface;
@ -44,5 +53,18 @@ return static function (ContainerConfigurator $containerConfigurator): void {
NodeTypeResolverInterface::class,
ReadNodeAnalyzerInterface::class,
SetListInterface::class,
ConflictingNameGuardInterface::class,
TypeParser::class,
RectorBetterReflectionSourceLocatorFactory::class,
AbstractTestCase::class,
PHPStanServicesFactory::class,
OutputStyleInterface::class,
FileFormatterInterface::class,
MethodCallManipulator::class,
// fix later - rector-symfony
PropertyConstructorInjectionManipulator::class,
// used in tests
\Rector\FileSystemRector\Parser\FileInfoParser::class,
\Rector\Defluent\NodeAnalyzer\SameClassMethodCallAnalyzer::class,
]);
};

View File

@ -1,47 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\BetterPhpDocParser\PhpDocParser;
use Iterator;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use Rector\BetterPhpDocParser\PhpDocParser\TypeNodeAnalyzer;
use Rector\Testing\PHPUnit\AbstractTestCase;
final class TypeNodeAnalyzerTest extends AbstractTestCase
{
/**
* @var string
*/
private const INT = 'int';
private TypeNodeAnalyzer $typeNodeAnalyzer;
protected function setUp(): void
{
$this->boot();
$this->typeNodeAnalyzer = $this->getService(TypeNodeAnalyzer::class);
}
/**
* @dataProvider provideDataForIntersectionAndNotNullable()
*/
public function testIsIntersectionAndNotNullable(TypeNode $typeNode, bool $expectedIs): void
{
$isIntersection = $this->typeNodeAnalyzer->isIntersectionAndNotNullable($typeNode);
$this->assertSame($expectedIs, $isIntersection);
}
/**
* @return Iterator<IntersectionTypeNode[]|bool[]>
*/
public function provideDataForIntersectionAndNotNullable(): Iterator
{
yield [new IntersectionTypeNode([new IdentifierTypeNode(self::INT)]), true];
yield [new IntersectionTypeNode([new NullableTypeNode(new IdentifierTypeNode(self::INT))]), false];
}
}

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocParser;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
/**
* @see \Rector\Tests\BetterPhpDocParser\PhpDocParser\TypeNodeAnalyzerTest
*/
final class TypeNodeAnalyzer
{
public function isIntersectionAndNotNullable(TypeNode $typeNode): bool
{
if (! $typeNode instanceof IntersectionTypeNode) {
return false;
}
foreach ($typeNode->types as $subType) {
if ($subType instanceof NullableTypeNode) {
return false;
}
}
return true;
}
}

View File

@ -1,72 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\FamilyTree\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\AstResolver;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class PropertyUsageAnalyzer
{
public function __construct(
private BetterNodeFinder $betterNodeFinder,
private FamilyRelationsAnalyzer $familyRelationsAnalyzer,
private NodeNameResolver $nodeNameResolver,
private AstResolver $astResolver
) {
}
public function isPropertyFetchedInChildClass(Property $property): bool
{
$className = $property->getAttribute(AttributeKey::CLASS_NAME);
if ($className === null) {
return false;
}
$scope = $property->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
return false;
}
$classReflection = $scope->getClassReflection();
if (! $classReflection instanceof ClassReflection) {
throw new ShouldNotHappenException();
}
if ($classReflection->isClass() && $classReflection->isFinal()) {
return false;
}
$propertyName = $this->nodeNameResolver->getName($property);
$childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection);
foreach ($childrenClassReflections as $childClassReflection) {
$childClass = $this->astResolver->resolveClassFromName($childClassReflection->getName());
if (! $childClass instanceof Class_) {
continue;
}
$isPropertyFetched = (bool) $this->betterNodeFinder->findFirst(
$childClass->stmts,
fn (Node $node): bool => $this->nodeNameResolver->isLocalPropertyFetchNamed($node, $propertyName)
);
if ($isPropertyFetched) {
return true;
}
}
return false;
}
}

View File

@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\ListReporting\Contract\Output;
use Rector\Core\Contract\Rector\RectorInterface;
interface ShowOutputFormatterInterface
{
/**
* @param RectorInterface[] $rectors
*/
public function list(array $rectors): void;
public function getName(): string;
}

View File

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\ListReporting\Output;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\ListReporting\Contract\Output\ShowOutputFormatterInterface;
final class ConsoleShowOutputFormatter implements ShowOutputFormatterInterface
{
/**
* @var string
*/
public const NAME = 'console';
public function __construct(
private OutputStyleInterface $outputStyle
) {
}
public function list(array $rectors): void
{
$rectorCount = count($rectors);
$this->outputStyle->title('Loaded Rector rules');
foreach ($rectors as $rector) {
$this->outputStyle->writeln(' * ' . $rector::class);
}
$message = sprintf('%d loaded Rectors', $rectorCount);
$this->outputStyle->success($message);
}
public function getName(): string
{
return self::NAME;
}
}

View File

@ -1,85 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Testing\PHPUnit;
use Nette\Utils\FileSystem;
use PHPUnit\Framework\Constraint\IsEqual;
/**
* Relaxes phpunit assertions to be forgiving about platform issues, like directory-separators or newlines.
* Mostly required to make assertion work on Windows.
*
* @note Cannot be used, as it breaks compatibility with PHPUnit 8 and 9 @see https://github.com/rectorphp/rector/issues/6709
*/
trait PlatformAgnosticAssertions
{
/**
* Asserts that two variables have the same type and value.
* Used on objects, it asserts that two variables reference
* the same object.
*
* @psalm-template ExpectedType
* @psalm-param ExpectedType $expected
* @psalm-assert =ExpectedType $actual
*/
public static function assertSame($expected, $actual, string $message = ''): void
{
if (is_string($expected)) {
$expected = self::normalize($expected);
}
if (is_string($actual)) {
$actual = self::normalize($actual);
}
parent::assertSame($expected, $actual, $message);
}
/**
* Asserts that the contents of a string is equal
* to the contents of a file.
*/
public static function assertStringEqualsFile(
string $expectedFile,
string $actualString,
string $message = ''
): void {
parent::assertFileExists($expectedFile, $message);
$expectedString = self::getNormalizedFileContents($expectedFile);
$isEqual = new IsEqual($expectedString);
$actualString = self::normalize($actualString);
parent::assertThat($actualString, $isEqual, $message);
}
/**
* Asserts that the contents of one file is equal to the contents of another
* file.
*/
public static function assertFileEquals(string $expected, string $actual, string $message = ''): void
{
static::assertFileExists($expected, $message);
static::assertFileExists($actual, $message);
$isEqual = new IsEqual(self::getNormalizedFileContents($expected));
static::assertThat(self::getNormalizedFileContents($actual), $isEqual, $message);
}
private static function normalize(string $string): array | string
{
$string = str_replace("\r\n", "\n", $string);
return str_replace(DIRECTORY_SEPARATOR, '/', $string);
}
private static function getNormalizedFileContents(string $filePath): string
{
$expectedString = FileSystem::read($filePath);
return self::normalize($expectedString);
}
}

View File

@ -13,6 +13,9 @@ use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @api
*/
final class TestingParser
{
public function __construct(

View File

@ -1,136 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\DependencyInjection\NodeRemover;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\PostRector\Collector\NodesToRemoveCollector;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class ClassMethodNodeRemover
{
public function __construct(
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private NodeNameResolver $nodeNameResolver,
private NodesToRemoveCollector $nodesToRemoveCollector
) {
}
public function removeClassMethodIfUseless(ClassMethod $classMethod): void
{
if ($classMethod->params !== []) {
return;
}
if ((array) $classMethod->stmts !== []) {
return;
}
$this->nodesToRemoveCollector->addNodeToRemove($classMethod);
}
public function removeParamFromMethodBody(ClassMethod $classMethod, Param $param): void
{
/** @var string $paramName */
$paramName = $this->nodeNameResolver->getName($param->var);
$this->simpleCallableNodeTraverser->traverseNodesWithCallable(
(array) $classMethod->stmts,
function (Node $node) use ($paramName) {
if (! $this->isParentConstructStaticCall($node)) {
return null;
}
/** @var StaticCall $node */
$this->removeParamFromArgs($node, $paramName);
if ($node->args === []) {
$this->nodesToRemoveCollector->addNodeToRemove($node);
}
return null;
}
);
foreach ((array) $classMethod->stmts as $key => $stmt) {
if ($stmt instanceof Expression) {
$stmt = $stmt->expr;
}
if (! $this->isParentConstructStaticCall($stmt)) {
continue;
}
/** @var StaticCall $stmt */
if ($stmt->args !== []) {
continue;
}
unset($classMethod->stmts[$key]);
}
$this->removeParamFromAssign($classMethod, $paramName);
}
private function isParentConstructStaticCall(Node $node): bool
{
if (! $node instanceof StaticCall) {
return false;
}
if (! $this->nodeNameResolver->isName($node->class, ObjectReference::PARENT()->getValue())) {
return false;
}
return $this->nodeNameResolver->isName($node->name, MethodName::CONSTRUCT);
}
private function removeParamFromArgs(StaticCall $staticCall, string $paramName): void
{
foreach ($staticCall->args as $key => $arg) {
if (! $arg instanceof Arg) {
continue;
}
if (! $this->nodeNameResolver->isName($arg->value, $paramName)) {
continue;
}
unset($staticCall->args[$key]);
}
}
private function removeParamFromAssign(ClassMethod $classMethod, string $paramName): void
{
foreach ((array) $classMethod->stmts as $key => $stmt) {
if ($stmt instanceof Expression) {
$stmt = $stmt->expr;
}
if (! $stmt instanceof Assign) {
continue;
}
if (! $stmt->expr instanceof Variable) {
continue;
}
if (! $this->nodeNameResolver->isName($stmt->expr, $paramName)) {
continue;
}
unset($classMethod->stmts[$key]);
}
}
}

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\DowngradePhp72\Contract\Rector;
interface DowngradeTypeRectorInterface
{
/**
* Name of the type to remove
*/
public function getTypeToRemove(): string;
}

View File

@ -1,58 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Naming;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\NodeTraverser;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class ArrayDimFetchRenamer
{
public function __construct(
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private NodeComparator $nodeComparator
) {
}
/**
* @see VariableRenamer::renameVariableInFunctionLike()
*/
public function renameToVariable(
ClassMethod $classMethod,
ArrayDimFetch $arrayDimFetch,
string $variableName
): void {
$this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $classMethod->stmts, function (
Node $node
) use ($arrayDimFetch, $variableName) {
// do not rename element above
if ($node->getLine() <= $arrayDimFetch->getLine()) {
return null;
}
if ($this->isScopeNesting($node)) {
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}
if (! $this->nodeComparator->areNodesEqual($node, $arrayDimFetch)) {
return null;
}
return new Variable($variableName);
});
}
private function isScopeNesting(Node $node): bool
{
return $node instanceof Closure || $node instanceof Function_ || $node instanceof ArrowFunction;
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\NodeFactory;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\ValueObject\MethodName;
final class SetUpFactory
{
public function __construct(
private NodeFactory $nodeFactory
) {
}
public function createParentStaticCall(): Expression
{
$parentSetupStaticCall = $this->nodeFactory->createStaticCall(ObjectReference::PARENT(), MethodName::SET_UP);
return new Expression($parentSetupStaticCall);
}
}

View File

@ -1,67 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Renaming\NodeManipulator;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\NodeNameResolver\NodeNameResolver;
/**
* This class renames node identifier, e.g. ClassMethod rename:
*
* -public function someMethod()
* +public function newMethod()
*/
final class IdentifierManipulator
{
public function __construct(
private NodeNameResolver $nodeNameResolver
) {
}
/**
* @param string[] $renameMethodMap
*/
public function renameNodeWithMap(
ClassConstFetch | MethodCall | PropertyFetch | StaticCall | ClassMethod $node,
array $renameMethodMap
): void {
$oldNodeMethodName = $this->resolveOldMethodName($node);
if ($oldNodeMethodName === null) {
return;
}
$node->name = new Identifier($renameMethodMap[$oldNodeMethodName]);
}
public function removeSuffix(
ClassConstFetch | MethodCall | PropertyFetch | StaticCall | ClassMethod $node,
string $suffixToRemove
): void {
$name = $this->nodeNameResolver->getName($node);
if ($name === null) {
return;
}
$newName = Strings::replace($name, sprintf('#%s$#', $suffixToRemove), '');
$node->name = new Identifier($newName);
}
private function resolveOldMethodName(
ClassConstFetch | MethodCall | PropertyFetch | StaticCall | ClassMethod $node
): ?string {
if ($node instanceof StaticCall || $node instanceof MethodCall) {
return $this->nodeNameResolver->getName($node->name);
}
return $this->nodeNameResolver->getName($node);
}
}

View File

@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\ValueObject;
use PHPStan\Type\ObjectType;
final class VariableMethodCallToServiceCall
{
/**
* @param mixed $argumentValue
*/
public function __construct(
private string $variableType,
private string $methodName,
private $argumentValue,
private string $serviceType,
private string $serviceMethodName
) {
}
public function getVariableObjectType(): ObjectType
{
return new ObjectType($this->variableType);
}
public function getMethodName(): string
{
return $this->methodName;
}
/**
* @return mixed
*/
public function getArgumentValue()
{
return $this->argumentValue;
}
public function getServiceType(): string
{
return $this->serviceType;
}
public function getServiceMethodName(): string
{
return $this->serviceMethodName;
}
}

View File

@ -4,16 +4,12 @@ declare(strict_types=1);
namespace Rector\Core\Console\Command;
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
use Rector\Core\Configuration\Option;
use Rector\Core\Console\Output\ShowOutputFormatterCollector;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\PostRector\Contract\Rector\ComplementaryRectorInterface;
use Rector\PostRector\Contract\Rector\PostRectorInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
final class ShowCommand extends Command
@ -23,7 +19,6 @@ final class ShowCommand extends Command
*/
public function __construct(
private OutputStyleInterface $outputStyle,
private ShowOutputFormatterCollector $showOutputFormatterCollector,
private array $rectors
) {
parent::__construct();
@ -32,30 +27,12 @@ final class ShowCommand extends Command
protected function configure(): void
{
$this->setDescription('Show loaded Rectors with their configuration');
$names = $this->showOutputFormatterCollector->getNames();
$description = sprintf('Select output format: "%s".', implode('", "', $names));
$this->addOption(
Option::OUTPUT_FORMAT,
'o',
InputOption::VALUE_OPTIONAL,
$description,
ConsoleOutputFormatter::NAME
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$outputFormat = (string) $input->getOption(Option::OUTPUT_FORMAT);
$this->outputStyle->title('Loaded Rector rules');
$this->reportLoadedRectors($outputFormat);
return Command::SUCCESS;
}
private function reportLoadedRectors(string $outputFormat): void
{
$rectors = array_filter(
$this->rectors,
function (RectorInterface $rector): bool {
@ -76,11 +53,17 @@ final class ShowCommand extends Command
PHP_EOL
);
$this->outputStyle->warning($warningMessage);
return;
return self::SUCCESS;
}
$outputFormatter = $this->showOutputFormatterCollector->getByName($outputFormat);
$outputFormatter->list($rectors);
$rectorCount = count($rectors);
foreach ($rectors as $rector) {
$this->outputStyle->writeln(' * ' . $rector::class);
}
$message = sprintf('%d loaded Rectors', $rectorCount);
$this->outputStyle->success($message);
return Command::SUCCESS;
}
}

View File

@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Console\Output;
use Rector\ListReporting\Contract\Output\ShowOutputFormatterInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
final class ShowOutputFormatterCollector
{
/**
* @var ShowOutputFormatterInterface[]
*/
private array $outputFormatters = [];
/**
* @param ShowOutputFormatterInterface[] $showOutputFormatters
*/
public function __construct(array $showOutputFormatters)
{
foreach ($showOutputFormatters as $showOutputFormatter) {
$this->outputFormatters[$showOutputFormatter->getName()] = $showOutputFormatter;
}
}
public function getByName(string $name): ShowOutputFormatterInterface
{
$this->ensureOutputFormatExists($name);
return $this->outputFormatters[$name];
}
/**
* @return int[]|string[]
*/
public function getNames(): array
{
return array_keys($this->outputFormatters);
}
private function ensureOutputFormatExists(string $name): void
{
if (isset($this->outputFormatters[$name])) {
return;
}
throw new InvalidConfigurationException(sprintf(
'Output formatter "%s" was not found. Pick one of "%s".',
$name,
implode('", "', $this->getNames())
));
}
}