MagicMethodRector: improve

This commit is contained in:
TomasVotruba 2017-09-30 15:28:49 +02:00
parent ddd03ebcda
commit c53bbd2ece
5 changed files with 68 additions and 25 deletions

View File

@ -9,6 +9,7 @@ use Rector\NodeTraverser\RectorNodeTraverser;
use Rector\NodeTraverser\ShutdownNodeTraverser;
use Rector\NodeTraverser\StandaloneTraverseNodeTraverser;
use Rector\NodeTraverserQueue\Exception\FileProcessingException;
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflection\ReflectionFunction;
use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound;
use SplFileInfo;
@ -80,7 +81,7 @@ final class NodeTraverserQueue
} catch (IdentifierNotFound $identifierNotFoundException) {
// could not locate function, skip and keep original
$identifierType = $identifierNotFoundException->getIdentifier()->getType()->getName();
if ($identifierType === ReflectionFunction::class) {
if (in_array($identifierType, [ReflectionFunction::class, ReflectionClass::class], true)) {
// keep original
return [$oldStmts, $oldStmts, $oldStmts];
}

View File

@ -38,7 +38,9 @@ final class DocBlockAnalyzer
/** @var Node $parentNode */
$parentNode = $node->getAttribute('parentNode');
$parentNode->setAttribute('origNode', null);
if ($parentNode) {
$parentNode->setAttribute('origNode', null);
}
$node->setAttribute('parentNode', null);
$node->setAttribute('origNode', null);

View File

@ -9,6 +9,9 @@ use Rector\Builder\MethodBuilder;
use Rector\Node\Attribute;
use Rector\NodeAnalyzer\DocBlockAnalyzer;
use Rector\Rector\AbstractRector;
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflection\ReflectionProperty;
use Roave\BetterReflection\Reflector\ClassReflector;
/**
* Catches @method annotations at childs of Nette\Object
@ -24,11 +27,11 @@ final class MagicMethodRector extends AbstractRector
* @var string
*/
private const MAGIC_METHODS_PATTERN = '~^
[ \t*]* @method [ \t]+
(?: [^\s(]+ [ \t]+ )?
(set|get|is|add) ([A-Z]\w*) [ \t]*
(?: \( [ \t]* ([^)$\s]+) )?
()~mx';
[ \t*]* @method [ \t]+
(?: [^\s(]+ [ \t]+ )?
(set|get|is|add) ([A-Z]\w*)
(?: ([ \t]* \() [ \t]* ([^)$\s]*) )?
()~mx';
/**
* @var mixed[]
@ -45,10 +48,24 @@ final class MagicMethodRector extends AbstractRector
*/
private $docBlockAnalyzer;
public function __construct(MethodBuilder $methodBuilder, DocBlockAnalyzer $docBlockAnalyzer)
{
/**
* @var ClassReflector
*/
private $classReflector;
/**
* @var ReflectionClass
*/
private $classReflection;
public function __construct(
MethodBuilder $methodBuilder,
DocBlockAnalyzer $docBlockAnalyzer,
ClassReflector $classReflector
) {
$this->methodBuilder = $methodBuilder;
$this->docBlockAnalyzer = $docBlockAnalyzer;
$this->classReflector = $classReflector;
}
public function isCandidate(Node $node): bool
@ -68,6 +85,10 @@ final class MagicMethodRector extends AbstractRector
return false;
}
/** @var string $className */
$className = $node->getAttribute(Attribute::CLASS_NAME);
$this->classReflection = $this->classReflector->reflect($className);
/** @var Doc $docComment */
$docComment = $docComments[0];
@ -127,27 +148,36 @@ final class MagicMethodRector extends AbstractRector
$name = $op . $prop;
$prop = strtolower($prop[0]) . substr($prop, 1) . ($op === 'add' ? 's' : '');
// @todo: file aware BetterReflection? - FileLocator
// use CurrentFileProvider? load in ProcessCommand, enable here
// if ($rc->hasProperty($prop) && ($rp = $rc->getProperty($prop)) && !$rp->isStatic()) {
// $rp->setAccessible(TRUE);
if ($op === 'get' || $op === 'is') {
$type = null;
$op = 'get';
} elseif (! $type
&& preg_match('#@var[ \t]+(\S+)' . ($op === 'add' ? '\[\]#' : '#'), $rp->getDocComment(), $match)
) {
$type = $match[1];
if (! $this->classReflection->hasProperty($prop)) {
continue;
}
if ($type && $currentNamespace && preg_match('#^[A-Z]\w+(\[|\||\z)#', $type)) {
$type = $currentNamespace . '\\' . $type;
}
/** @var ReflectionProperty $propertyReflection */
$propertyReflection = $this->classReflection->getProperty($prop);
$methods[$name] = [
'propertyType' => $type,
'propertyName' => $prop,
];
if ($propertyReflection && ! $propertyReflection->isStatic()) {
if ($op === 'get' || $op === 'is') {
$type = null;
$op = 'get';
} elseif (! $type
&& preg_match('#@var[ \t]+(\S+)' . ($op === 'add' ? '\[\]#' : '#'), $propertyReflection->getDocComment(), $match)
) {
$type = $match[1];
}
if ($type && $currentNamespace && preg_match('#^[A-Z]\w+(\[|\||\z)#', $type)) {
$type = $currentNamespace . '\\' . $type;
}
$methods[$name] = [
'propertyType' => $type,
'propertyName' => $prop,
];
}
}
return $methods;

View File

@ -6,8 +6,15 @@ use Nette\Object;
class SomeClass extends Object
{
private $value;
private $anotherValue;
public function getValue()
{
return $this->value;
}
public function getAnotherValue(): int
{
return $this->anotherValue;
}
}

View File

@ -6,7 +6,10 @@ use Nette\Object;
/**
* @method getValue()
* @method int getAnotherValue()
*/
class SomeClass extends Object
{
private $value;
private $anotherValue;
}