Skip to content

Commit

Permalink
release PHP 7.2 downgraded
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Oct 24, 2023
1 parent ed4843a commit d9942db
Show file tree
Hide file tree
Showing 641 changed files with 60,270 additions and 880 deletions.
9 changes: 0 additions & 9 deletions .editorconfig

This file was deleted.

File renamed without changes.
13 changes: 0 additions & 13 deletions .gitignore

This file was deleted.

35 changes: 19 additions & 16 deletions app/ClassNameResolver.php
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
<?php

declare(strict_types=1);

declare (strict_types=1);
namespace TomasVotruba\ClassLeak;

use PhpParser\NodeTraverser;
use PhpParser\Parser;
use ClassLeak202310\PhpParser\NodeTraverser;
use ClassLeak202310\PhpParser\Parser;
use TomasVotruba\ClassLeak\NodeDecorator\FullyQualifiedNameNodeDecorator;
use TomasVotruba\ClassLeak\NodeVisitor\ClassNameNodeVisitor;

/**
* @see \TomasVotruba\ClassLeak\Tests\ClassNameResolver\ClassNameResolverTest
*/
final class ClassNameResolver
{
public function __construct(
private readonly Parser $parser,
private readonly FullyQualifiedNameNodeDecorator $fullyQualifiedNameNodeDecorator
) {
/**
* @readonly
* @var \PhpParser\Parser
*/
private $parser;
/**
* @readonly
* @var \TomasVotruba\ClassLeak\NodeDecorator\FullyQualifiedNameNodeDecorator
*/
private $fullyQualifiedNameNodeDecorator;
public function __construct(Parser $parser, FullyQualifiedNameNodeDecorator $fullyQualifiedNameNodeDecorator)
{
$this->parser = $parser;
$this->fullyQualifiedNameNodeDecorator = $fullyQualifiedNameNodeDecorator;
}

public function resolveFromFromFilePath(string $filePath): ?string
public function resolveFromFromFilePath(string $filePath) : ?string
{
/** @var string $fileContents */
$fileContents = file_get_contents($filePath);

$fileContents = \file_get_contents($filePath);
$stmts = $this->parser->parse($fileContents);
if ($stmts === null) {
return null;
}

$this->fullyQualifiedNameNodeDecorator->decorate($stmts);

$classNameNodeVisitor = new ClassNameNodeVisitor();
$nodeTraverser = new NodeTraverser();
$nodeTraverser->addVisitor($classNameNodeVisitor);
$nodeTraverser->traverse($stmts);

return $classNameNodeVisitor->getClassName();
}
}
127 changes: 58 additions & 69 deletions app/Commands/CheckCommand.php
Original file line number Diff line number Diff line change
@@ -1,113 +1,102 @@
<?php

declare(strict_types=1);

declare (strict_types=1);
namespace TomasVotruba\ClassLeak\Commands;

use Closure;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use ClassLeak202310\Symfony\Component\Console\Command\Command;
use ClassLeak202310\Symfony\Component\Console\Input\InputArgument;
use ClassLeak202310\Symfony\Component\Console\Input\InputInterface;
use ClassLeak202310\Symfony\Component\Console\Input\InputOption;
use ClassLeak202310\Symfony\Component\Console\Output\OutputInterface;
use ClassLeak202310\Symfony\Component\Console\Style\SymfonyStyle;
use TomasVotruba\ClassLeak\Filtering\PossiblyUnusedClassesFilter;
use TomasVotruba\ClassLeak\Finder\ClassNamesFinder;
use TomasVotruba\ClassLeak\Finder\PhpFilesFinder;
use TomasVotruba\ClassLeak\Reporting\UnusedClassReporter;
use TomasVotruba\ClassLeak\UseImportsResolver;

final class CheckCommand extends Command
{
public function __construct(
private readonly ClassNamesFinder $classNamesFinder,
private readonly UseImportsResolver $useImportsResolver,
private readonly PossiblyUnusedClassesFilter $possiblyUnusedClassesFilter,
private readonly UnusedClassReporter $unusedClassReporter,
private readonly SymfonyStyle $symfonyStyle,
private readonly PhpFilesFinder $phpFilesFinder,
) {
/**
* @readonly
* @var \TomasVotruba\ClassLeak\Finder\ClassNamesFinder
*/
private $classNamesFinder;
/**
* @readonly
* @var \TomasVotruba\ClassLeak\UseImportsResolver
*/
private $useImportsResolver;
/**
* @readonly
* @var \TomasVotruba\ClassLeak\Filtering\PossiblyUnusedClassesFilter
*/
private $possiblyUnusedClassesFilter;
/**
* @readonly
* @var \TomasVotruba\ClassLeak\Reporting\UnusedClassReporter
*/
private $unusedClassReporter;
/**
* @readonly
* @var \Symfony\Component\Console\Style\SymfonyStyle
*/
private $symfonyStyle;
/**
* @readonly
* @var \TomasVotruba\ClassLeak\Finder\PhpFilesFinder
*/
private $phpFilesFinder;
public function __construct(ClassNamesFinder $classNamesFinder, UseImportsResolver $useImportsResolver, PossiblyUnusedClassesFilter $possiblyUnusedClassesFilter, UnusedClassReporter $unusedClassReporter, SymfonyStyle $symfonyStyle, PhpFilesFinder $phpFilesFinder)
{
$this->classNamesFinder = $classNamesFinder;
$this->useImportsResolver = $useImportsResolver;
$this->possiblyUnusedClassesFilter = $possiblyUnusedClassesFilter;
$this->unusedClassReporter = $unusedClassReporter;
$this->symfonyStyle = $symfonyStyle;
$this->phpFilesFinder = $phpFilesFinder;
parent::__construct();
}

protected function configure(): void
protected function configure() : void
{
$this->setName('check');
$this->setDescription('Check classes that are not used in any config and in the code');

$this->addArgument(
'paths',
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
'Files and directories to analyze'
);
$this->addOption(
'skip-type',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Class types that should be skipped'
);

$this->addOption(
'skip-suffix',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
'Class suffix that should be skipped'
);
$this->addArgument('paths', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Files and directories to analyze');
$this->addOption('skip-type', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Class types that should be skipped');
$this->addOption('skip-suffix', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Class suffix that should be skipped');
}

protected function execute(InputInterface $input, OutputInterface $output): int
protected function execute(InputInterface $input, OutputInterface $output) : int
{
/** @var string[] $paths */
$paths = (array) $input->getArgument('paths');

/** @var string[] $typesToSkip */
$typesToSkip = (array) $input->getOption('skip-type');

/** @var string[] $suffixesToSkip */
$suffixesToSkip = (array) $input->getOption('skip-suffix');

$phpFilePaths = $this->phpFilesFinder->findPhpFiles($paths);

$this->symfonyStyle->progressStart(count($phpFilePaths));
$this->symfonyStyle->progressStart(\count($phpFilePaths));
$this->symfonyStyle->newLine();

$usedNames = $this->resolveUsedClassNames($phpFilePaths, function (): void {
$usedNames = $this->resolveUsedClassNames($phpFilePaths, function () : void {
$this->symfonyStyle->progressAdvance();
});

$existingFilesWithClasses = $this->classNamesFinder->resolveClassNamesToCheck($phpFilePaths);

$possiblyUnusedFilesWithClasses = $this->possiblyUnusedClassesFilter->filter(
$existingFilesWithClasses,
$usedNames,
$typesToSkip,
$suffixesToSkip
);

return $this->unusedClassReporter->reportResult(
$possiblyUnusedFilesWithClasses,
$existingFilesWithClasses
);
$possiblyUnusedFilesWithClasses = $this->possiblyUnusedClassesFilter->filter($existingFilesWithClasses, $usedNames, $typesToSkip, $suffixesToSkip);
return $this->unusedClassReporter->reportResult($possiblyUnusedFilesWithClasses, $existingFilesWithClasses);
}

/**
* @param string[] $phpFilePaths
* @return string[]
*/
private function resolveUsedClassNames(array $phpFilePaths, Closure $progressClosure): array
private function resolveUsedClassNames(array $phpFilePaths, Closure $progressClosure) : array
{
$usedNames = [];

foreach ($phpFilePaths as $phpFilePath) {
$currentUsedNames = $this->useImportsResolver->resolve($phpFilePath);
$usedNames = array_merge($usedNames, $currentUsedNames);

$usedNames = \array_merge($usedNames, $currentUsedNames);
$progressClosure();
}

$usedNames = array_unique($usedNames);
sort($usedNames);

$usedNames = \array_unique($usedNames);
\sort($usedNames);
return $usedNames;
}
}
50 changes: 18 additions & 32 deletions app/DependencyInjection/ContainerFactory.php
Original file line number Diff line number Diff line change
@@ -1,66 +1,52 @@
<?php

declare(strict_types=1);

declare (strict_types=1);
namespace TomasVotruba\ClassLeak\DependencyInjection;

use Illuminate\Container\Container;
use PhpParser\Parser;
use PhpParser\ParserFactory;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Style\SymfonyStyle;
use ClassLeak202310\Illuminate\Container\Container;
use ClassLeak202310\PhpParser\Parser;
use ClassLeak202310\PhpParser\ParserFactory;
use ClassLeak202310\Symfony\Component\Console\Application;
use ClassLeak202310\Symfony\Component\Console\Input\ArrayInput;
use ClassLeak202310\Symfony\Component\Console\Output\ConsoleOutput;
use ClassLeak202310\Symfony\Component\Console\Output\NullOutput;
use ClassLeak202310\Symfony\Component\Console\Style\SymfonyStyle;
use TomasVotruba\ClassLeak\Commands\CheckCommand;

final class ContainerFactory
{
/**
* @var string[]
*/
private const COMMAND_NAMES_TO_HIDE = ['completion', 'help', 'list'];

/**
* @api
*/
public function create(): Container
public function create() : Container
{
$container = new Container();

$container->singleton(Parser::class, static function (): Parser {
$container->singleton(Parser::class, static function () : Parser {
$parserFactory = new ParserFactory();
return $parserFactory->create(ParserFactory::PREFER_PHP7);
});

$container->singleton(
SymfonyStyle::class,
static function (): SymfonyStyle {
// use null output ofr tests to avoid printing
$consoleOutput = defined('PHPUNIT_COMPOSER_INSTALL') ? new NullOutput() : new ConsoleOutput();
return new SymfonyStyle(new ArrayInput([]), $consoleOutput);
}
);

$container->singleton(Application::class, function (Container $container): Application {
$container->singleton(SymfonyStyle::class, static function () : SymfonyStyle {
// use null output ofr tests to avoid printing
$consoleOutput = \defined('PHPUNIT_COMPOSER_INSTALL') ? new NullOutput() : new ConsoleOutput();
return new SymfonyStyle(new ArrayInput([]), $consoleOutput);
});
$container->singleton(Application::class, function (Container $container) : Application {
/** @var CheckCommand $checkCommand */
$checkCommand = $container->make(CheckCommand::class);

$application = new Application();
$application->add($checkCommand);

$this->hideDefaultCommands($application);

return $application;
});

return $container;
}

/**
* @see https://tomasvotruba.com/blog/how-make-your-tool-commands-list-easy-to-read
*/
private function hideDefaultCommands(Application $application): void
private function hideDefaultCommands(Application $application) : void
{
foreach (self::COMMAND_NAMES_TO_HIDE as $commandNameToHide) {
$commandToHide = $application->get($commandNameToHide);
Expand Down
9 changes: 4 additions & 5 deletions app/FileSystem/StaticRelativeFilePathHelper.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
<?php

declare(strict_types=1);

declare (strict_types=1);
namespace TomasVotruba\ClassLeak\FileSystem;

/**
* @see \TomasVotruba\ClassLeak\Tests\FileSystem\StaticRelativeFilePathHelperTest
*/
final class StaticRelativeFilePathHelper
{
public static function resolveFromCwd(string $filePath): string
public static function resolveFromCwd(string $filePath) : string
{
// make path relative with native PHP
$relativeFilePath = (string) realpath($filePath);
return str_replace(getcwd() . DIRECTORY_SEPARATOR, '', $relativeFilePath);
$relativeFilePath = (string) \realpath($filePath);
return \str_replace(\getcwd() . \DIRECTORY_SEPARATOR, '', $relativeFilePath);
}
}
Loading

0 comments on commit d9942db

Please sign in to comment.