Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BetterNodeFinder + NodeRemover added #113

Merged
merged 33 commits into from
Oct 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
78903bc
fix Name node resolving
TomasVotruba Oct 26, 2017
b39efbf
fix Name node resolving
TomasVotruba Oct 26, 2017
91559ab
raw init of ExpressionRemover
TomasVotruba Oct 26, 2017
4cc5e84
add BetterNodeFinder, change ExpressionRemover to NodeRemover
TomasVotruba Oct 26, 2017
e1efffe
make test pass
TomasVotruba Oct 26, 2017
aa67e22
insurance
TomasVotruba Oct 26, 2017
109da12
AbstractRector: drop decouple shouldRemoverNode logic
TomasVotruba Oct 26, 2017
5d1b918
[NodeTraverserQueue] add BetterNodeFinder tests
TomasVotruba Oct 26, 2017
5a18744
add BetterNodeFinder to AbstractRector
TomasVotruba Oct 26, 2017
fbe86bf
drop dead code
TomasVotruba Oct 26, 2017
af68eaf
use BetterNodeFinder instead of Printer magic
TomasVotruba Oct 26, 2017
5bfa37d
misc
TomasVotruba Oct 26, 2017
8451443
misc
TomasVotruba Oct 26, 2017
779966b
add segfault test
TomasVotruba Oct 26, 2017
f015173
fix segfault in PropertyFetchTypeResolver
TomasVotruba Oct 26, 2017
304e22d
misc
TomasVotruba Oct 26, 2017
31da6ea
details
TomasVotruba Oct 26, 2017
3d7e03a
[NodeTraverserQueue] add test for weird cloning use case
TomasVotruba Oct 27, 2017
d59ffe2
add failing test for CloningVisitor
TomasVotruba Oct 27, 2017
0d6abda
add IdentifierRector test
TomasVotruba Oct 27, 2017
200ab47
extend IdentifierRector test
TomasVotruba Oct 27, 2017
4b244db
IdentifierRector: run just once
TomasVotruba Oct 27, 2017
70bd97c
ClassReplacerRector test
TomasVotruba Oct 27, 2017
9979677
fix cs
TomasVotruba Oct 27, 2017
be26c7e
fixing PerNodeTypeResolver for property access
TomasVotruba Oct 27, 2017
b240ead
[ReflectionDocBlock] make NamespaceAnalyzer work with use aliases
TomasVotruba Oct 27, 2017
9f9ed78
[PropertyFetchTypeResolver] add object property reflection
TomasVotruba Oct 27, 2017
ea2a918
[NodeTypeResolver] deal with nested property
TomasVotruba Oct 27, 2017
46c2009
make it run for nested array property access
TomasVotruba Oct 27, 2017
47a5625
minimize code for failing clone of NodeTraverserQueue
TomasVotruba Oct 27, 2017
2974ce2
[ReflectionDocBlock] decouple AnnotationRemover
TomasVotruba Oct 27, 2017
33a8969
[NodeTypeResolver] fix multitypes for properties, resolve via DocBloc…
TomasVotruba Oct 28, 2017
9f41017
make CloningNodeVistior pass
TomasVotruba Oct 28, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"beberlei/assert": "^2.7",
"doctrine/annotations": "^1.5",
"nette/utils": "^2.4",
"nikic/php-parser": "4.0.x-dev#f5de7f9 as 3.1.1",
"nikic/php-parser": "v4.0.0alpha1 as 3.1.1",
"phpdocumentor/reflection-docblock": "^4.1",
"phpdocumentor/type-resolver": "^0.4.0",
"rector/better-reflection": "^3.0",
"rector/better-reflection": "^3.0.2",
"symfony/console": "^3.3",
"symfony/dependency-injection": "^3.3",
"symplify/package-builder": "^2.5"
Expand All @@ -35,7 +35,6 @@
"Rector\\": "src",
"Rector\\BetterReflection\\": "packages/BetterReflection/src",
"Rector\\ReflectionDocBlock\\": "packages/ReflectionDocBlock/src",
"Rector\\DeprecatedAnnotation\\": "packages/DeprecatedAnnotation/src",
"Rector\\NodeTypeResolver\\": "packages/NodeTypeResolver/src",
"Rector\\NodeTraverserQueue\\": "packages/NodeTraverserQueue/src",
"Rector\\DeprecationExtractor\\": "packages/DeprecationExtractor/src",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public function getMethodReturnType(string $class, string $methodCallName): ?str

if ($methodReflection) {
$returnType = $methodReflection->getReturnType();

if ($returnType) {
return (string) $returnType;
}
Expand Down
79 changes: 79 additions & 0 deletions packages/BetterReflection/src/Reflector/PropertyReflector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php declare(strict_types=1);

namespace Rector\BetterReflection\Reflector;

use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\Object_;
use Rector\BetterReflection\Reflection\ReflectionProperty;
use Rector\BetterReflection\Reflector\Exception\IdentifierNotFound;

final class PropertyReflector
{
/**
* @var SmartClassReflector
*/
private $smartClassReflector;

/**
* @var mixed[][]
*/
private $cachedClassPropertyTypes = [];

public function __construct(SmartClassReflector $smartClassReflector)
{
$this->smartClassReflector = $smartClassReflector;
}

public function reflectClassProperty(string $class, string $method): ?ReflectionProperty
{
try {
$classReflection = $this->smartClassReflector->reflect($class);
} catch (IdentifierNotFound $identifierNotFoundException) {
return null;
}

if ($classReflection === null) {
return null;
}

return $classReflection->getImmediateProperties()[$method] ?? null;
}

public function getPropertyType(string $class, string $property): ?string
{
if (isset($this->cachedClassPropertyTypes[$class][$property])) {
return $this->cachedClassPropertyTypes[$class][$property];
}

$propertyReflection = $this->reflectClassProperty($class, $property);

$type = null;
if ($propertyReflection) {
$type = $this->resolveTypeFromReflectionProperty($propertyReflection);
}

return $this->cachedClassPropertyTypes[$class][$property] = $type;
}

private function resolveTypeFromReflectionProperty(ReflectionProperty $reflectionProperty): ?string
{
$types = $reflectionProperty->getDocBlockTypes();

if (! isset($types[0])) {
return null;
}

if ($types[0] instanceof Array_) {
$valueType = $types[0]->getValueType();
if ($valueType instanceof Object_) {
return ltrim((string) $valueType->getFqsen(), '\\');
}
}

if ($types[0] instanceof Object_) {
return ltrim((string) $types[0]->getFqsen(), '\\');
}

return null;
}
}
62 changes: 62 additions & 0 deletions packages/NodeTraverserQueue/src/BetterNodeFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php declare(strict_types=1);

namespace Rector\NodeTraverserQueue;

use PhpParser\Node;
use PhpParser\NodeFinder;
use Rector\Node\Attribute;

final class BetterNodeFinder
{
/**
* @var NodeFinder
*/
private $nodeFinder;

public function __construct(NodeFinder $nodeFinder)
{
$this->nodeFinder = $nodeFinder;
}

public function findFirstAncestorInstanceOf(Node $node, string $type): ?Node
{
/** @var Node|null $currentNode */
$currentNode = $node->getAttribute(Attribute::PARENT_NODE);

while ($currentNode !== null) {
if ($currentNode instanceof $type) {
return $currentNode;
}

$currentNode = $currentNode->getAttribute(Attribute::PARENT_NODE);
}

return null;
}

/**
* @param Node|Node[] $nodes
* @return Node[]
*/
public function findInstanceOf($nodes, string $type): array
{
return $this->nodeFinder->findInstanceOf($nodes, $type);
}

/**
* @param Node|Node[] $nodes
*/
public function findFirstInstanceOf($nodes, string $type): ?Node
{
return $this->nodeFinder->findFirstInstanceOf($nodes, $type);
}

/**
* @param Node|Node[] $nodes
* @return Node[]
*/
public function find($nodes, callable $filter): array
{
return $this->nodeFinder->find($nodes, $filter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

class SomeClass
{
public function someAction()
{
$variable = 5;
}
}
41 changes: 41 additions & 0 deletions packages/NodeTraverserQueue/tests/BetterNodeFinderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types=1);

namespace Rector\NodeTraverserQueue\Tests;

use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use Rector\NodeTypeResolver\Tests\AbstractNodeTypeResolverTest;

final class BetterNodeFinderTest extends AbstractNodeTypeResolverTest
{
/**
* @var Node[]
*/
private $nodes = [];

protected function setUp(): void
{
parent::setUp();

$this->nodes = $this->getNodesForFile(__DIR__ . '/BetterNodeFinderSource/SomeFile.php.inc');
}

public function testFindFirstAncestorInstanceOf(): void
{
$variableNode = $this->betterNodeFinder->findFirstInstanceOf($this->nodes, Variable::class);
$classNode = $this->betterNodeFinder->findFirstInstanceOf($this->nodes, Class_::class);

$classLikeNode = $this->betterNodeFinder->findFirstAncestorInstanceOf($variableNode, ClassLike::class);
$this->assertSame($classLikeNode, $classNode);
}

public function testFindMissingFirstAncestorInstanceOf(): void
{
$variableNode = $this->betterNodeFinder->findFirstInstanceOf($this->nodes, Variable::class);

$this->assertNull($this->betterNodeFinder->findFirstAncestorInstanceOf($variableNode, Array_::class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

function someMethod()
{
$someAnonymousClass = new class
extends NodeVisitorAbstract
{
private $propertyFollowedByBlankLine;

private $property;
};
}
64 changes: 64 additions & 0 deletions packages/NodeTraverserQueue/tests/NodeTraverserQueueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php declare(strict_types=1);

namespace Rector\NodeTraverserQueue\Tests;

use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use Rector\Contract\Parser\ParserInterface;
use Rector\Printer\FormatPerservingPrinter;
use Rector\Tests\AbstractContainerAwareTestCase;
use SplFileInfo;
use Throwable;

final class NodeTraverserQueueTest extends AbstractContainerAwareTestCase
{
/**
* @var Lexer
*/
private $lexer;

/**
* @var ParserInterface
*/
private $parser;

/**
* @var SplFileInfo
*/
private $fileInfo;

/**
* @var FormatPerservingPrinter
*/
private $formatPerservingPrinter;

protected function setUp(): void
{
$this->lexer = $this->container->get(Lexer::class);
$this->parser = $this->container->get(ParserInterface::class);
$this->fileInfo = new SplFileInfo(__DIR__ . '/NodeTraverserQueueSource/Before.php.inc');
$this->formatPerservingPrinter = $this->container->get(FormatPerservingPrinter::class);
}

public function testRaw(): void
{
try {
$oldStmts = $this->parser->parseFile($this->fileInfo->getRealPath());
$oldTokens = $this->lexer->getTokens();

$cloningNodeTraverser = new NodeTraverser;
$cloningNodeTraverser->addVisitor(new CloningVisitor);

$newStmts = $cloningNodeTraverser->traverse($oldStmts);

$processedFileContent = $this->formatPerservingPrinter->printToString($newStmts, $oldStmts, $oldTokens);
$this->assertStringEqualsFile($this->fileInfo->getRealPath(), $processedFileContent);
} catch (Throwable $throwable) {
$this->markTestSkipped(sprintf(
'Test %s failed.',
__METHOD__
));
}
}
}
16 changes: 13 additions & 3 deletions packages/NodeTypeResolver/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
# Node Type Resolver

This package detects `class`, type `class_node` and `$variable` or `$this->property` types and adds them to all relevant nodes.
This package detects **class, interface and trait types** for classes, variables and properties. Those types and added via `setAttribute(Attribute::TYPES)`, so you always now where you are.

Class type is added to all nodes inside it, so you always now where you are.
Anonymous classes are included, e.g.:

Anonymous classes are skipped.
```php
$someAnonymousClass = new class extends SomeClass
{
}
```

includes types:

```php
['SomeClass']
```


## How it works?
Expand Down
13 changes: 7 additions & 6 deletions packages/NodeTypeResolver/src/NodeVisitor/NamespaceResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\NodeFinder;
use PhpParser\NodeVisitorAbstract;
use Rector\Node\Attribute;
use Rector\NodeTraverserQueue\BetterNodeFinder;

final class NamespaceResolver extends NodeVisitorAbstract
{
Expand All @@ -22,18 +22,18 @@ final class NamespaceResolver extends NodeVisitorAbstract
private $namespaceNode;

/**
* @var NodeFinder
* @var BetterNodeFinder
*/
private $nodeFinder;
private $betterNodeFinder;

/**
* @var Use_[]
*/
private $useNodes = [];

public function __construct(NodeFinder $nodeFinder)
public function __construct(BetterNodeFinder $betterNodeFinder)
{
$this->nodeFinder = $nodeFinder;
$this->betterNodeFinder = $betterNodeFinder;
}

/**
Expand All @@ -43,14 +43,15 @@ public function beforeTraverse(array $nodes): void
{
$this->namespaceName = null;
$this->namespaceNode = null;
$this->useNodes = [];
}

public function enterNode(Node $node): void
{
if ($node instanceof Namespace_) {
$this->namespaceName = $node->name ? $node->name->toString() : null;
$this->namespaceNode = $node;
$this->useNodes = $this->nodeFinder->findInstanceOf($node, Use_::class);
$this->useNodes = $this->betterNodeFinder->findInstanceOf($node, Use_::class);
}

$node->setAttribute(Attribute::NAMESPACE_NAME, $this->namespaceName);
Expand Down
Loading