[TriggerExtractor] add DeprecationDetector

This commit is contained in:
TomasVotruba 2017-09-06 01:21:44 +02:00
parent 602d8d2290
commit e94c2957d3
7 changed files with 242 additions and 377 deletions

View File

@ -2,12 +2,11 @@
namespace Rector\TriggerExtractor\Console\Command;
use Nette\Utils\Finder;
use Rector\TriggerExtractor\TriggerExtractor;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\SplFileInfo;
final class ExtractCommand extends Command
{
@ -21,6 +20,18 @@ final class ExtractCommand extends Command
*/
private const ARGUMENT_SOURCE_NAME = 'source';
/**
* @var TriggerExtractor
*/
private $triggerExtractor;
public function __construct(TriggerExtractor $triggerExtractor)
{
$this->triggerExtractor = $triggerExtractor;
parent::__construct();
}
protected function configure(): void
{
$this->setName(self::NAME);
@ -35,23 +46,11 @@ final class ExtractCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int
{
$source = $input->getArgument(self::ARGUMENT_SOURCE_NAME);
$files = $this->findPhpFilesInDirectories($source);
$foundDeprecations = $this->triggerExtractor->scanDirectories($source);
dump($files);
dump($foundDeprecations);
die;
return 0;
}
/**
* @param string[] $directories
* @return SplFileInfo[] array
*/
private function findPhpFilesInDirectories(array $directories): array
{
$finder = Finder::find('*.php')
->in($directories);
return iterator_to_array($finder->getIterator());
}
}

View File

@ -0,0 +1,90 @@
<?php declare(strict_types=1);
namespace Rector\TriggerExtractor\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\MagicConst\Method;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\NodeVisitorAbstract;
final class DeprecationDetector extends NodeVisitorAbstract
{
public function enterNode(Node $node): void
{
if (! $this->isTriggerErrorUserDeprecated($node)) {
return;
}
/** @var FuncCall $funcCallNode */
$funcCallNode = $node;
$messageNode = $funcCallNode->args[0]->value;
$message = '';
if ($messageNode instanceof Concat) {
$message .= $this->processConcatNode($messageNode->left);
$message .= $this->processConcatNode($messageNode->right);
}
// @todo add to: deprecation collector
// return $message;
}
private function isTriggerErrorUserDeprecated(Node $node): bool
{
if (! $node instanceof FuncCall) {
return false;
}
if (! $node->name instanceof Name) {
return false;
}
if ($node->name->toString() !== 'trigger_error') {
return false;
}
if (count($node->args) !== 2) {
return false;
}
if (! $node->args[1]->value instanceof ConstFetch) {
return false;
}
/** @var ConstFetch $constFetchNode */
$constFetchNode = $node->args[1]->value;
return $constFetchNode->name->toString() === 'E_USER_DEPRECATED';
}
private function processConcatNode(Node $node): string
{
if ($node instanceof Method) { // get method name in stirng, e.g. "getValue()"
$classMethodNode = $this->findParentOfType($node, ClassMethod::class);
return $classMethodNode->name->name;
}
if ($node instanceof String_) {
return $node->value;
}
// @todo implement
}
private function findParentOfType(Node $node, string $type): ClassMethod
{
$parentNode = $node->getAttribute('parent');
while (! is_a($parentNode , $type, true)) {
$parentNode = $parentNode->getAttribute('parent');
}
return $parentNode;
}
}

View File

@ -1,11 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\TriggerExtractor\Scanner;
final class Scanner
{
public function scanDirectory(string $directory): array
{
}
}

View File

@ -0,0 +1,72 @@
<?php declare(strict_types=1);
namespace Rector\TriggerExtractor;
use Rector\Contract\Parser\ParserInterface;
use Rector\NodeTraverser\MainNodeTraverser;
use Rector\NodeTraverser\StandaloneTraverseNodeTraverser;
use Rector\TriggerExtractor\NodeVisitor\DeprecationDetector;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
final class TriggerExtractor
{
/**
* @var ParserInterface
*/
private $parser;
/**
* @var MainNodeTraverser
*/
private $mainNodeTraverser;
/**
* @var StandaloneTraverseNodeTraverser
*/
private $standaloneTraverseNodeTraverser;
public function __construct(
ParserInterface $parser,
MainNodeTraverser $mainNodeTraverser,
DeprecationDetector $deprecationDetector,
StandaloneTraverseNodeTraverser $standaloneTraverseNodeTraverser
) {
$this->mainNodeTraverser = $mainNodeTraverser;
$this->mainNodeTraverser->addVisitor($deprecationDetector);
$this->standaloneTraverseNodeTraverser = $standaloneTraverseNodeTraverser;
$this->parser = $parser;
}
/**
* @param string[] $directories
* @return array
*/
public function scanDirectories(array $directories): array
{
$files = $this->findPhpFilesInDirectories($directories);
foreach ($files as $file) {
$nodes = $this->parser->parseFile($file->getRealPath());
$this->standaloneTraverseNodeTraverser->traverse($nodes);
$this->mainNodeTraverser->traverse($nodes);
die;
}
die;
}
/**
* @param string[] $directories
* @return SplFileInfo[] array
*/
private function findPhpFilesInDirectories(array $directories): array
{
$finder = Finder::create()
->files()
->name('*.php')
->in($directories);
return iterator_to_array($finder->getIterator());
}
}

View File

@ -1,350 +0,0 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\DI;
use Nette;
/**
* Definition used by ContainerBuilder.
*
* @property string|null $class
* @property Statement|null $factory
* @property Statement[] $setup
*/
final class ServiceDefinition
{
use Nette\SmartObject;
const
IMPLEMENT_MODE_CREATE = 'create',
IMPLEMENT_MODE_GET = 'get';
/** @var array */
public $parameters = [];
/** @var string|null class or interface name */
private $type;
/** @var Statement|null */
private $factory;
/** @var Statement[] */
private $setup = [];
/** @var array */
private $tags = [];
/** @var bool|string[] */
private $autowired = true;
/** @var bool */
private $dynamic = false;
/** @var string|null interface name */
private $implement;
/** @var string|null create | get */
private $implementMode;
/** @var callable */
private $notifier = 'pi'; // = noop
/**
* @param string|null
* @return static
* @deprecated
*/
public function setClass($type)
{
($this->notifier)();
$this->type = $type;
if (func_num_args() > 1) {
trigger_error(__METHOD__ . '() second parameter $args is deprecated, use setFactory()', E_USER_DEPRECATED);
if ($args = func_get_arg(1)) {
$this->setFactory($type, $args);
}
}
return $this;
}
/**
* @return string|null
* @deprecated
*/
public function getClass()
{
return $this->type;
}
/**
* @param string|null
* @return static
*/
public function setType($type)
{
($this->notifier)();
$this->type = $type;
return $this;
}
/**
* @return string|null
*/
public function getType()
{
return $this->type;
}
/**
* @return static
*/
public function setFactory($factory, array $args = [])
{
($this->notifier)();
$this->factory = $factory instanceof Statement ? $factory : new Statement($factory, $args);
return $this;
}
/**
* @return Statement|null
*/
public function getFactory()
{
return $this->factory;
}
/**
* @return string|array|ServiceDefinition|null
*/
public function getEntity()
{
return $this->factory ? $this->factory->getEntity() : null;
}
/**
* @return static
*/
public function setArguments(array $args = [])
{
if (!$this->factory) {
$this->factory = new Statement($this->type);
}
$this->factory->arguments = $args;
return $this;
}
/**
* @param Statement[]
* @return static
*/
public function setSetup(array $setup)
{
foreach ($setup as $v) {
if (!$v instanceof Statement) {
throw new Nette\InvalidArgumentException('Argument must be Nette\DI\Statement[].');
}
}
$this->setup = $setup;
return $this;
}
/**
* @return Statement[]
*/
public function getSetup(): array
{
return $this->setup;
}
/**
* @return static
*/
public function addSetup($entity, array $args = [])
{
$this->setup[] = $entity instanceof Statement ? $entity : new Statement($entity, $args);
return $this;
}
/**
* @return static
*/
public function setParameters(array $params)
{
$this->parameters = $params;
return $this;
}
public function getParameters(): array
{
return $this->parameters;
}
/**
* @return static
*/
public function setTags(array $tags)
{
$this->tags = $tags;
return $this;
}
public function getTags(): array
{
return $this->tags;
}
/**
* @return static
*/
public function addTag(string $tag, $attr = true)
{
$this->tags[$tag] = $attr;
return $this;
}
/**
* @return mixed
*/
public function getTag(string $tag)
{
return $this->tags[$tag] ?? null;
}
/**
* @param bool|string|string[]
* @return static
*/
public function setAutowired($state = true)
{
($this->notifier)();
$this->autowired = is_string($state) || is_array($state) ? (array) $state : (bool) $state;
return $this;
}
/**
* @return bool|string[]
*/
public function isAutowired()
{
return $this->autowired;
}
/**
* @return bool|string[]
*/
public function getAutowired()
{
return $this->autowired;
}
/**
* @return static
*/
public function setDynamic(bool $state = true)
{
$this->dynamic = $state;
return $this;
}
public function isDynamic(): bool
{
return $this->dynamic;
}
/**
* @return static
*/
public function setImplement(string $interface)
{
($this->notifier)();
$this->implement = $interface;
return $this;
}
/**
* @return string|null
*/
public function getImplement()
{
return $this->implement;
}
/**
* @return static
*/
public function setImplementMode(string $mode)
{
if (!in_array($mode, [self::IMPLEMENT_MODE_CREATE, self::IMPLEMENT_MODE_GET], true)) {
throw new Nette\InvalidArgumentException('Argument must be get|create.');
}
$this->implementMode = $mode;
return $this;
}
/**
* @return string|null
*/
public function getImplementMode()
{
return $this->implementMode;
}
/** @deprecated */
public function setInject(bool $state = true)
{
trigger_error(__METHOD__ . "() is deprecated, use addTag('inject')", E_USER_DEPRECATED);
return $this->addTag(Extensions\InjectExtension::TAG_INJECT, $state);
}
/**
* @internal
*/
public function setNotifier(callable $notifier)
{
$this->notifier = $notifier;
}
public function __clone()
{
$this->factory = unserialize(serialize($this->factory));
$this->setup = unserialize(serialize($this->setup));
$this->notifier = 'pi';
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\DI;
use Nette;
final class ServiceDefinition
{
/**
* @param string|null
* @return static
* @deprecated
*/
public function setClass($type)
{
($this->notifier)();
$this->type = $type;
if (func_num_args() > 1) {
trigger_error(__METHOD__ . '() second parameter $args is deprecated, use setFactory()', E_USER_DEPRECATED);
if ($args = func_get_arg(1)) {
$this->setFactory($type, $args);
}
}
return $this;
}
/** @deprecated */
public function setInject(bool $state = true)
{
trigger_error(__METHOD__ . "() is deprecated, use addTag('inject')", E_USER_DEPRECATED);
return $this->addTag(Extensions\InjectExtension::TAG_INJECT, $state);
}
}

View File

@ -0,0 +1,25 @@
<?php declare(strict_types=1);
namespace Rector\TriggerExtractor\Tests;
use Rector\Tests\AbstractContainerAwareTestCase;
use Rector\TriggerExtractor\TriggerExtractor;
final class TriggerExtractorTest extends AbstractContainerAwareTestCase
{
/**
* @var TriggerExtractor
*/
private $triggerExtractor;
protected function setUp(): void
{
$this->triggerExtractor = $this->container->get(TriggerExtractor::class);
}
public function test(): void
{
$foundDeprecations = $this->triggerExtractor->scanDirectories([__DIR__ . '/TriggerExtractorSource']);
$this->assertCount(2, $foundDeprecations);
}
}