mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 05:48:21 +01:00
Merge pull request #582 from rectorphp/node-type-resolver-tests
[NodeTypeResolver] Add standalone tests
This commit is contained in:
commit
5de8b58bea
@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
# trailing whitespaces
|
||||
sed -i -E 's#\s+$##g' config/level/*/*.yml docs/*.md README.md
|
||||
sed -i -E 's#\s+$##g' config/level/*/*.yml docs/*.md packages/*/README.md README.md
|
||||
|
@ -60,6 +60,7 @@
|
||||
"Rector\\Sylius\\Tests\\": "packages/Sylius/tests",
|
||||
"Rector\\PHPUnit\\Tests\\": "packages/PHPUnit/tests",
|
||||
"Rector\\PhpParser\\Tests\\": "packages/PhpParser/tests",
|
||||
"Rector\\Utils\\Tests\\": "packages/Utils/tests",
|
||||
"Rector\\Doctrine\\Tests\\": "packages/Doctrine/tests",
|
||||
"Rector\\YamlRector\\Tests\\": "packages/YamlRector/tests"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@ final class PhpDocInfoFqnTypeDecorator extends AbstractPhpDocInfoDecorator
|
||||
return $node;
|
||||
}
|
||||
|
||||
// @todo check PHPStan for this
|
||||
/** @var IdentifierTypeNode $node */
|
||||
$node->name = $this->namespaceAnalyzer->resolveTypeToFullyQualified(
|
||||
$node->name,
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Node Type Resolver
|
||||
|
||||
This package detects **class, interface and trait types** for classes, variables and properties. Those types are resolved by `NodeTypeResolver` service. It uses PHPStan for `PhpParser\Node\Expr` nodes and own type resolvers for other nodes like `PhpParser\Node\Stmt\Class_`, `PhpParser\Node\Stmt\Interface_` or `PhpParser\Node\Stmt\Trait_`.
|
||||
This package detects **class, interface and trait types** for classes, variables and properties. Those types are resolved by `NodeTypeResolver` service. It uses PHPStan for `PhpParser\Node\Expr` nodes and own type resolvers for other nodes like `PhpParser\Node\Stmt\Class_`, `PhpParser\Node\Stmt\Interface_` or `PhpParser\Node\Stmt\Trait_`.
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
@ -8,43 +9,104 @@ This package detects **class, interface and trait types** for classes, variables
|
||||
composer require rector/node-type-resolver
|
||||
```
|
||||
|
||||
## Usage
|
||||
You first need to integrate `Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator` to you application. It will traverse nodes and decorate with attributes that you can use right away and also attributes that are required for `Rector\NodeTypeResolver\NodeTypeResolver`.
|
||||
|
||||
### 1. Get Types of Node
|
||||
This package works best in Symfony Kernel application, but is also available in standalone use thanks to decoupled container factory.
|
||||
|
||||
### A. Symfony Application
|
||||
|
||||
Import `services.yml` in your Symfony config:
|
||||
|
||||
```yaml
|
||||
# your-app/config.yml
|
||||
imports:
|
||||
- { resource: 'vendor/rector/node-type-resolver/config/services.yml' }
|
||||
```
|
||||
|
||||
Require `Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator` in the constructor:
|
||||
|
||||
```php
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
final class SomeNodeProcessor
|
||||
namespace YourApp;
|
||||
|
||||
use PhpParser\Parser;
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
* @var Parser
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
private $parser;
|
||||
|
||||
public function __construct(NodeTypeResolver $nodeTypeResolver)
|
||||
{
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
/**
|
||||
* @var NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator
|
||||
*/
|
||||
private $nodeScopeAndMetadataDecorator;
|
||||
|
||||
public function __construct(
|
||||
Parser $parser,
|
||||
NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator
|
||||
) {
|
||||
$this->parser = $parser;
|
||||
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
|
||||
}
|
||||
|
||||
public function process(Node $node)
|
||||
public function run(): void
|
||||
{
|
||||
/** @var string[] $nodeTypes */
|
||||
$nodeTypes = $this->nodeTypeResolver->resolve($node);
|
||||
$someFilePath = __DIR__ . '/SomeFile.php';
|
||||
$nodes = $this->parser->parse(file_get_contents($someFilePath));
|
||||
|
||||
if (in_array('Nette\Application\UI\Form', $nodeTypes, true) {
|
||||
// this is Nette\Application\UI\Form variable
|
||||
$decoratedNodes = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, $someFilePath);
|
||||
|
||||
foreach ($decoratedNodes as $node) {
|
||||
$className = $node->getAttribute(MetadataAttribute::CLASS_NAME);
|
||||
// "string" with class name
|
||||
var_dump($className);
|
||||
}
|
||||
|
||||
// continue
|
||||
|
||||
// do whatever you need :)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
...in any Rector you create.
|
||||
### B. Standalone PHP Code
|
||||
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
use Rector\NodeTypeResolver\DependencyInjection\NodeTypeResolverContainerFactory;
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
|
||||
use PhpParser\ParserFactory;
|
||||
|
||||
$phpParser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||
|
||||
$someFilePath = __DIR__ . '/SomeFile.php';
|
||||
$nodes = $phpParser->parse(file_get_contents($someFilePath));
|
||||
|
||||
$nodeTypeResolverContainer = (new NodeTypeResolverContainerFactory())->create();
|
||||
/** @var NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator */
|
||||
$nodeScopeAndMetadataDecorator = $nodeTypeResolverContainer->get(NodeScopeAndMetadataDecorator::class);
|
||||
$decoratedNodes = $nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, $someFilePath);
|
||||
|
||||
foreach ($decoratedNodes as $node) {
|
||||
$className = $node->getAttribute(MetadataAttribute::CLASS_NAME);
|
||||
// "string" with class name
|
||||
var_dump($className);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 2. Helper Attributes
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
After this integration you have new attributes you can work with.
|
||||
|
||||
### Attributes
|
||||
|
||||
These attributes are always available anywhere inside the Node tree. That means that `CLASS_NAME` is available **in every node that is in the class**. That way you can easily get class name on `Property` node.
|
||||
|
||||
@ -53,12 +115,14 @@ These attributes are always available anywhere inside the Node tree. That means
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
//@todo examples of dump
|
||||
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
|
||||
// string name of current namespace
|
||||
$namespaceName = $node->setAttribute(MetadataAttribute::NAMESPACE_NAME, $this->namespaceName);
|
||||
|
||||
// instance of "PhpParser\Node\Stmt\Namespace_"
|
||||
// instance of "PhpParser\Node\Stmt\Namespace_"
|
||||
$namespaceNode = $node->setAttribute(MetadataAttribute::NAMESPACE_NODE, $this->namespaceNode);
|
||||
|
||||
// instances of "PhpParser\Node\Stmt\Use_"
|
||||
@ -70,6 +134,8 @@ $useNodes = $node->setAttribute(MetadataAttribute::USE_NODES, $this->useNodes);
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
//@todo examples of dump
|
||||
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
|
||||
// string name of current class
|
||||
@ -89,6 +155,8 @@ $parentClassName = $node->getAttribute(MetadataAttribute::PARENT_CLASS_NAME);
|
||||
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
|
||||
//@todo examples of dump
|
||||
|
||||
// string name of current method
|
||||
$methodName = $node->getAttribute(MetadataAttribute::METHOD_NAME);
|
||||
|
||||
@ -99,68 +167,32 @@ $methodNode = $node->getAttribute(MetadataAttribute::METHOD_NODE);
|
||||
$methodCallName = $node->getAttribute(MetadataAttribute::METHOD_NAME);
|
||||
```
|
||||
|
||||
#### Setup
|
||||
### Get Types of Node
|
||||
|
||||
1. Import `services.yml` in your config
|
||||
`Rector\NodeTypeResolver\NodeTypeResolver` helps you detect object types for any node that can have one.
|
||||
|
||||
```yaml
|
||||
# your-app/config.yml
|
||||
imports:
|
||||
- { resource: 'vendor/rector/node-type-resolver/config/services.yml' }
|
||||
```
|
||||
|
||||
2. Use `Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator` wherever you need.
|
||||
Get it via constructor or `$container->get(Rector\NodeTypeResolver\NodeTypeResolver::class)`;
|
||||
|
||||
```php
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace YourApp;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
|
||||
use PhpParser\Parser;
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
|
||||
// previously processed nodes
|
||||
$nodes = [...];
|
||||
/** @var NodeTypeResolver $nodeTypeResolver */
|
||||
$nodeTypeResolver = ...;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
/**
|
||||
* @var Parser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* @var NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator
|
||||
*/
|
||||
private $nodeScopeAndMetadataDecorator;
|
||||
|
||||
public function __construct(
|
||||
Parser $parser,
|
||||
NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator
|
||||
) {
|
||||
$this->parser = $parser;
|
||||
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$someFilePath = __DIR__ . '/SomeFile.php';
|
||||
$someFileContent = file_get_contents($someFilePath);
|
||||
$nodes = $this->parser->parse($someFileContent);
|
||||
|
||||
$decoratedNodes = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, $someFilePath);
|
||||
|
||||
foreach ($decoratedNodes as $node) {
|
||||
$className = $node->getAttribute(MetadataAttribute::CLASS_NAME);
|
||||
// "string" with class name
|
||||
var_dump($className);
|
||||
}
|
||||
|
||||
// do whatever you need :)
|
||||
foreach ($nodes as $node) {
|
||||
if ($node instanceof Class_) {
|
||||
$classNodeTypes = $nodeTypeResolver->resolve($node);
|
||||
var_dump($classNodeTypes); // array of strings
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And that's it!
|
||||
|
||||
### Inspiration
|
||||
|
||||
- [PHPStanScopeVisitor](https://github.com/silverstripe/silverstripe-upgrader/blob/532182b23e854d02e0b27e68ebc394f436de0682/src/UpgradeRule/PHP/Visitor/PHPStanScopeVisitor.php) in [SilverStripe](https://github.com/silverstripe/) - Thank you ❤️️
|
||||
Huge thanks for inspiration of this integration belongs to [PHPStanScopeVisitor](https://github.com/silverstripe/silverstripe-upgrader/blob/532182b23e854d02e0b27e68ebc394f436de0682/src/UpgradeRule/PHP/Visitor/PHPStanScopeVisitor.php) by [SilverStripe](https://github.com/silverstripe/) - Thank you ❤️️ !
|
||||
|
||||
|
@ -8,14 +8,14 @@
|
||||
"require": {
|
||||
"php": "^7.1",
|
||||
"nikic/php-parser": "^4.0.3",
|
||||
"phpstan/phpstan": "^0.10.2",
|
||||
"phpstan/phpstan": "^0.10.3",
|
||||
"symfony/dependency-injection": "^3.4|^4.0",
|
||||
"symfony/finder": "^3.4|^4.0",
|
||||
"symplify/better-phpdoc-parser": "^4.7",
|
||||
"symplify/package-builder": "^4.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.1"
|
||||
"phpunit/phpunit": "^7.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@ -0,0 +1,24 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\DependencyInjection;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
final class NodeTypeResolverContainerFactory
|
||||
{
|
||||
public function create(): ContainerInterface
|
||||
{
|
||||
$kernel = new NodeTypeResolverKernel();
|
||||
$kernel->boot();
|
||||
|
||||
return $kernel->getContainer();
|
||||
}
|
||||
|
||||
public function createWithConfig(string $config): ContainerInterface
|
||||
{
|
||||
$kernel = new NodeTypeResolverKernel($config);
|
||||
$kernel->boot();
|
||||
|
||||
return $kernel->getContainer();
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
final class NodeTypeResolverKernel extends Kernel
|
||||
{
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $config;
|
||||
|
||||
public function __construct(?string $config = null)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
parent::__construct('dev', true);
|
||||
}
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader): void
|
||||
{
|
||||
$loader->load(__DIR__ . '/../../src/config/services.yml');
|
||||
|
||||
if ($this->config) {
|
||||
$loader->load($this->config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BundleInterface[]
|
||||
*/
|
||||
public function registerBundles(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getCacheDir(): string
|
||||
{
|
||||
return sys_get_temp_dir() . '/_rector_node_type_resolver_cache';
|
||||
}
|
||||
|
||||
public function getLogDir(): string
|
||||
{
|
||||
return sys_get_temp_dir() . '/_rector_type_resolver_test_log';
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@ namespace Rector\NodeTypeResolver\Metadata;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use Rector\NodeTraverserQueue\BetterNodeFinder;
|
||||
use Rector\NodeTypeResolver\Contract\Metadata\NodeDecoratorInterface;
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
|
||||
final class NamespaceNodeDecorator implements NodeDecoratorInterface
|
||||
{
|
||||
|
@ -1,12 +1,31 @@
|
||||
imports:
|
||||
# to cover prefixed rector and projects autoload - monorepo
|
||||
- { resource: '../../../../vendor/symplify/better-phpdoc-parser/src/config/services.yml', ignore_errors: true }
|
||||
# @todo resolve location for standalone package
|
||||
|
||||
|
||||
services:
|
||||
_defaults:
|
||||
# for "Rector\NodeTypeResolver\NodeTypeResolverFactory" standalone usage
|
||||
public: true
|
||||
autowire: true
|
||||
|
||||
Rector\NodeTypeResolver\:
|
||||
resource: '../'
|
||||
exclude: '../{Contract}'
|
||||
exclude: '../{Contract,DependencyInjection/NodeTypeResolverKernel.php,DependencyInjection/NodeTypeResolverContainerFactory.php}'
|
||||
|
||||
Rector\PhpParser\CurrentNodeProvider: ~
|
||||
|
||||
Rector\Php\TypeAnalyzer: ~
|
||||
Rector\BetterPhpDocParser\NodeAnalyzer\DocBlockAnalyzer: ~
|
||||
Rector\Printer\BetterStandardPrinter: ~
|
||||
Rector\FileSystem\FilesFinder: ~
|
||||
Symplify\PackageBuilder\Parameter\ParameterProvider: ~
|
||||
PhpParser\NodeVisitor\CloningVisitor: ~
|
||||
PhpParser\NodeFinder: ~
|
||||
Rector\Utils\BetterNodeFinder: ~
|
||||
|
||||
# factory to remove dependency on CompilerPass and make install DX smoother
|
||||
Rector\NodeTypeResolver\NodeTypeResolver:
|
||||
factory: ['@Rector\NodeTypeResolver\NodeTypeResolverFactory', 'create']
|
||||
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Rector\NodeTypeResolver\DependencyInjection\NodeTypeResolverContainerFactory;
|
||||
|
||||
abstract class AbstractNodeTypeResolverContainerAwareTestCase extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private static $cachedContainer;
|
||||
|
||||
/**
|
||||
* Constructs a test case with the given name.
|
||||
*
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
public function __construct(?string $name = null, array $data = [], string $dataName = '')
|
||||
{
|
||||
if (self::$cachedContainer === null) {
|
||||
self::$cachedContainer = (new NodeTypeResolverContainerFactory())->createWithConfig(
|
||||
__DIR__ . '/config/config.tests.yml'
|
||||
);
|
||||
}
|
||||
|
||||
$this->container = self::$cachedContainer;
|
||||
|
||||
parent::__construct($name, $data, $dataName);
|
||||
}
|
||||
}
|
@ -3,14 +3,14 @@
|
||||
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\NodeTraverserQueue\BetterNodeFinder;
|
||||
use Rector\NodeTraverserQueue\NodeTraverserQueue;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\Tests\AbstractContainerAwareTestCase;
|
||||
use Rector\NodeTypeResolver\Tests\AbstractNodeTypeResolverContainerAwareTestCase;
|
||||
use Rector\NodeTypeResolver\Tests\StandaloneNodeTraverserQueue;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Symplify\PackageBuilder\Parameter\ParameterProvider;
|
||||
|
||||
abstract class AbstractNodeTypeResolverTest extends AbstractContainerAwareTestCase
|
||||
abstract class AbstractNodeTypeResolverTest extends AbstractNodeTypeResolverContainerAwareTestCase
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
@ -23,9 +23,9 @@ abstract class AbstractNodeTypeResolverTest extends AbstractContainerAwareTestCa
|
||||
protected $nodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @var NodeTraverserQueue
|
||||
* @var StandaloneNodeTraverserQueue
|
||||
*/
|
||||
private $nodeTraverserQueue;
|
||||
private $standaloneNodeTraverserQueue;
|
||||
|
||||
/**
|
||||
* @var ParameterProvider
|
||||
@ -35,7 +35,7 @@ abstract class AbstractNodeTypeResolverTest extends AbstractContainerAwareTestCa
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->betterNodeFinder = $this->container->get(BetterNodeFinder::class);
|
||||
$this->nodeTraverserQueue = $this->container->get(NodeTraverserQueue::class);
|
||||
$this->standaloneNodeTraverserQueue = $this->container->get(StandaloneNodeTraverserQueue::class);
|
||||
$this->parameterProvider = $this->container->get(ParameterProvider::class);
|
||||
$this->nodeTypeResolver = $this->container->get(NodeTypeResolver::class);
|
||||
}
|
||||
@ -59,8 +59,6 @@ abstract class AbstractNodeTypeResolverTest extends AbstractContainerAwareTestCa
|
||||
|
||||
$this->parameterProvider->changeParameter('source', [$file]);
|
||||
|
||||
[$newStmts,] = $this->nodeTraverserQueue->processFileInfo($fileInfo);
|
||||
|
||||
return $newStmts;
|
||||
return $this->standaloneNodeTraverserQueue->processFileInfo($fileInfo);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\Tests;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Parser;
|
||||
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
|
||||
final class StandaloneNodeTraverserQueue
|
||||
{
|
||||
/**
|
||||
* @var Parser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* @var NodeScopeAndMetadataDecorator
|
||||
*/
|
||||
private $nodeScopeAndMetadataDecorator;
|
||||
|
||||
public function __construct(Parser $parser, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
*/
|
||||
public function processFileInfo(SplFileInfo $fileInfo): array
|
||||
{
|
||||
$nodes = $this->parser->parse($fileInfo->getContents());
|
||||
|
||||
return $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, $fileInfo->getRealPath());
|
||||
}
|
||||
}
|
12
packages/NodeTypeResolver/tests/config/config.tests.yml
Normal file
12
packages/NodeTypeResolver/tests/config/config.tests.yml
Normal file
@ -0,0 +1,12 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
public: true
|
||||
|
||||
PhpParser\ParserFactory: ~
|
||||
PhpParser\Parser:
|
||||
factory: ['@PhpParser\ParserFactory', 'create']
|
||||
arguments:
|
||||
$kind: !php/const PhpParser\ParserFactory::PREFER_PHP7
|
||||
|
||||
Rector\NodeTypeResolver\Tests\StandaloneNodeTraverserQueue: ~
|
@ -12,11 +12,11 @@ use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\BetterPhpDocParser\NodeAnalyzer\DocBlockAnalyzer;
|
||||
use Rector\Node\MethodCallNodeFactory;
|
||||
use Rector\Node\NodeFactory;
|
||||
use Rector\NodeTraverserQueue\BetterNodeFinder;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\Sensio\Helper\TemplateGuesser;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
|
||||
final class TemplateAnnotationRector extends AbstractRector
|
||||
{
|
||||
|
@ -7,12 +7,12 @@ use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\Node\NodeFactory;
|
||||
use Rector\NodeAnalyzer\MethodCallAnalyzer;
|
||||
use Rector\NodeTraverserQueue\BetterNodeFinder;
|
||||
use Rector\NodeTypeResolver\Node\MetadataAttribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\Symfony\Bridge\NodeAnalyzer\ControllerMethodAnalyzer;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
|
||||
final class GetRequestRector extends AbstractRector
|
||||
{
|
||||
|
25
packages/Utils/composer.json
Normal file
25
packages/Utils/composer.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "rector/utils",
|
||||
"description": "Util services like NodeFinder.",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{ "name": "Tomas Votruba", "email": "tomas.vot@gmail.com", "homepage": "https://tomasvotruba.com" }
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.1",
|
||||
"nikic/php-parser": "^4.0.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Rector\\Utils\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Rector\\Utils\\Tests\\": "tests"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTraverserQueue;
|
||||
namespace Rector\Utils;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeFinder;
|
@ -1,3 +1,5 @@
|
||||
services:
|
||||
Rector\Utils\:
|
||||
resource: '../'
|
||||
|
||||
PhpParser\NodeFinder: ~
|
||||
|
@ -1,16 +1,26 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTraverserQueue\Tests;
|
||||
namespace Rector\Utils\Tests\BetterNodeFinder;
|
||||
|
||||
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\PerNodeTypeResolver\AbstractNodeTypeResolverTest;
|
||||
use PhpParser\NodeFinder;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\ParserFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Rector\NodeTypeResolver\NodeVisitor\ParentAndNextNodeVisitor;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
|
||||
final class BetterNodeFinderTest extends AbstractNodeTypeResolverTest
|
||||
final class BetterNodeFinderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var Node[]
|
||||
*/
|
||||
@ -18,9 +28,8 @@ final class BetterNodeFinderTest extends AbstractNodeTypeResolverTest
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->nodes = $this->getNodesForFile(__DIR__ . '/BetterNodeFinderSource/SomeFile.php.inc');
|
||||
$this->betterNodeFinder = new BetterNodeFinder(new NodeFinder());
|
||||
$this->nodes = $this->createNodesFromFile(__DIR__ . '/Source/SomeFile.php.inc');
|
||||
}
|
||||
|
||||
public function testFindFirstAncestorInstanceOf(): void
|
||||
@ -29,6 +38,9 @@ final class BetterNodeFinderTest extends AbstractNodeTypeResolverTest
|
||||
$variableNode = $this->betterNodeFinder->findFirstInstanceOf($this->nodes, Variable::class);
|
||||
$classNode = $this->betterNodeFinder->findFirstInstanceOf($this->nodes, Class_::class);
|
||||
|
||||
$this->assertInstanceOf(Variable::class, $variableNode);
|
||||
$this->assertInstanceOf(Class_::class, $classNode);
|
||||
|
||||
$classLikeNode = $this->betterNodeFinder->findFirstAncestorInstanceOf($variableNode, ClassLike::class);
|
||||
$this->assertSame($classLikeNode, $classNode);
|
||||
}
|
||||
@ -40,4 +52,18 @@ final class BetterNodeFinderTest extends AbstractNodeTypeResolverTest
|
||||
|
||||
$this->assertNull($this->betterNodeFinder->findFirstAncestorInstanceOf($variableNode, Array_::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
*/
|
||||
private function createNodesFromFile(string $filePath): array
|
||||
{
|
||||
$phpParser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||
$nodes = $phpParser->parse(file_get_contents($filePath));
|
||||
|
||||
$nodeTraverser = new NodeTraverser();
|
||||
$nodeTraverser->addVisitor(new ParentAndNextNodeVisitor());
|
||||
|
||||
return $nodeTraverser->traverse($nodes);
|
||||
}
|
||||
}
|
10
phpstan.neon
10
phpstan.neon
@ -1,8 +1,7 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
# the # after each ignored error is the number of occurrences
|
||||
|
||||
- '#Parameter \#2 \$filePath of method Rector\\NodeTypeResolver\\(.*?)::decorateNodesFromFile\(\) expects string, string\|false given#'
|
||||
- '#Parameter \#2 \$filePath of method Rector\\(.*?)::decorateNodesFromFile\(\) expects string, string\|false given#'
|
||||
|
||||
# missuse of interface and class
|
||||
- '#Parameter \#1 (.*?) expects Symfony\\Component\\DependencyInjection\\ContainerBuilder, Symfony\\Component\\DependencyInjection\\ContainerInterface given#' # 2
|
||||
@ -63,7 +62,7 @@ parameters:
|
||||
|
||||
- '#Method Rector\\Node\\NodeFactory::createNullConstant\(\) should return PhpParser\\Node\\Expr\\ConstFetch but returns PhpParser\\Node\\Expr#' # 1
|
||||
- '#Method Rector\\Node\\NodeFactory::createNamespace\(\) should return PhpParser\\Node\\Stmt\\Namespace_ but returns PhpParser\\Node#' # 1
|
||||
- '#Method Rector\\NodeTraverserQueue\\BetterNodeFinder::findFirstAncestorInstanceOf\(\) should return PhpParser\\Node\|null but returns object#' # 1
|
||||
- '#Method Rector\\Utils\\BetterNodeFinder::findFirstAncestorInstanceOf\(\) should return PhpParser\\Node\|null but returns object#' # 1
|
||||
- '#Property Rector\\NodeTypeResolver\\Metadata\\NamespaceNodeDecorator::\$useNodes \(array<PhpParser\\Node\\Stmt\\Use_>\) does not accept array<PhpParser\\Node>#' # 1
|
||||
- '#Parameter \#1 \$node of method Rector\\NodeTypeResolver\\NodeTypeResolver::resolve\(\) expects PhpParser\\Node, PhpParser\\Node\\Expr|string given#' # 3
|
||||
|
||||
@ -74,6 +73,9 @@ parameters:
|
||||
# tests or coding standars?
|
||||
- '#Constructor of class [\s\S]+ has an unused parameter \$html#' # 2
|
||||
|
||||
# tests - known values
|
||||
- '#Parameter \#1 \$code of method PhpParser\\Parser::parse\(\) expects string, string\|false given#' # 1
|
||||
|
||||
# too strict
|
||||
- '#Parameter \#1 \$currentWorkingDirectory of class PHPStan\\DependencyInjection\\ContainerFactory constructor expects string, string\|false given#' # 1
|
||||
|
||||
@ -81,4 +83,4 @@ parameters:
|
||||
# test files
|
||||
- '*tests/Rector/MethodCall/MethodNameReplacerRector/**/SomeClass.php'
|
||||
- '*packages/BetterReflection/tests/Reflector/NotLoadedSource/SomeClass.php'
|
||||
- 'packages/NodeTypeResolver/tests/PerNodeTypeResolver/VariableTypeResolver/Source/NewClass.php'
|
||||
- 'packages/NodeTypeResolver/tests/PerNodeTypeResolver/VariableTypeResolver/Source/NewClass.php'
|
||||
|
@ -6,8 +6,8 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\NodeTraverser;
|
||||
use Rector\NodeTraverserQueue\BetterNodeFinder;
|
||||
use Rector\PhpParser\NodeVisitor\ExpressionAddingNodeVisitor;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
use SplObjectStorage;
|
||||
|
||||
/**
|
||||
|
@ -5,9 +5,9 @@ namespace Rector\Rector\DomainDrivenDesign\ValueObjectRemover;
|
||||
use PhpParser\Node;
|
||||
use Rector\BetterPhpDocParser\NodeAnalyzer\DocBlockAnalyzer;
|
||||
use Rector\BetterPhpDocParser\NodeAnalyzer\NamespaceAnalyzer;
|
||||
use Rector\NodeTraverserQueue\BetterNodeFinder;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\Utils\BetterNodeFinder;
|
||||
|
||||
abstract class AbstractValueObjectRemoverRector extends AbstractRector
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user