Skip to content

Commit

Permalink
add DynamicSourceLocator that is shared by PHPStan and Rector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Feb 23, 2021
1 parent 9f28fe5 commit 2f3a909
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 44 deletions.
3 changes: 0 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@
"nette/robot-loader": "^3.2",
"nette/utils": "^3.2",
"nikic/php-parser": "^4.10.4",
"ondrejmirtes/better-reflection": "^4.3.50",
"jetbrains/phpstorm-stubs": "2020.2 as dev-master",
"roave/signature": "1.4 as 1.1.0",
"phpstan/phpdoc-parser": "^0.4.9",
"phpstan/phpstan": "^0.12.76",
"phpstan/phpstan-phpunit": "^0.12.17",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use Rector\DoctrineAnnotationGenerated\PhpDocNode\ConstantReferenceIdentifierRestorer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use ReflectionClass;
use ReflectionProperty;
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
use Throwable;
Expand Down Expand Up @@ -51,12 +50,14 @@ public function __construct(
ConstantReferenceIdentifierRestorer $constantReferenceIdentifierRestorer,
NodeNameResolver $nodeNameResolver,
Reader $reader,
ReflectionProvider $reflectionProvider
ReflectionProvider $reflectionProvider,
PrivatesAccessor $privatesAccessor
) {
$this->reader = $reader;
$this->nodeNameResolver = $nodeNameResolver;
$this->constantReferenceIdentifierRestorer = $constantReferenceIdentifierRestorer;
$this->reflectionProvider = $reflectionProvider;
$this->privatesAccessor = $privatesAccessor;
}

public function readAnnotation(Node $node, string $annotationClass): ?object
Expand Down Expand Up @@ -100,7 +101,6 @@ public function readPropertyAnnotation(Property $property, string $annotationCla
try {
// covers cases like https://github.com/rectorphp/rector/issues/3046

// @todo this will require original reflection
/** @var object[] $propertyAnnotations */
$propertyAnnotations = $this->reader->getPropertyAnnotations($propertyReflection);
return $this->matchNextAnnotation($propertyAnnotations, $annotationClassName, $property);
Expand All @@ -122,8 +122,7 @@ private function readMethodAnnotation(ClassMethod $classMethod, string $annotati
$methodReflection = $reflectionClass->getNativeMethod($methodName);

// @see https://github.com/phpstan/phpstan-src/commit/5fad625b7770b9c5beebb19ccc1a493839308fb4
$privatesAccessor = new PrivatesAccessor();
$nativeMethodReflection = $privatesAccessor->getPrivateProperty($methodReflection, 'reflection');
$nativeMethodReflection = $this->privatesAccessor->getPrivateProperty($methodReflection, 'reflection');

try {
// covers cases like https://github.com/rectorphp/rector/issues/3046
Expand Down Expand Up @@ -159,9 +158,7 @@ private function createClassReflectionFromNode(Class_ $class): ClassReflection
$className = $this->nodeNameResolver->getName($class);

// covers cases like https://github.com/rectorphp/rector/issues/3230#issuecomment-683317288

return $this->reflectionProvider->getClass($className);
// return new ReflectionClass($className);
}

/**
Expand Down Expand Up @@ -211,10 +208,7 @@ private function getNativePropertyReflection(Property $property): ?ReflectionPro
$propertyReflection = $classReflection->getProperty($propertyName, $propertyScope);

// @see https://github.com/phpstan/phpstan-src/commit/5fad625b7770b9c5beebb19ccc1a493839308fb4
$privatesAccessor = new PrivatesAccessor();
return $privatesAccessor->getPrivateProperty($propertyReflection, 'reflection');

// return new ReflectionProperty($className, $propertyName);
return $this->privatesAccessor->getPrivateProperty($propertyReflection, 'reflection');
} catch (Throwable $throwable) {
// in case of PHPUnit property or just-added property
return null;
Expand Down
10 changes: 9 additions & 1 deletion packages/node-type-resolver/config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\NodeTypeResolver\DependencyInjection\PHPStanServicesFactory;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocator;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

Expand All @@ -29,7 +31,10 @@
->autoconfigure();

$services->load('Rector\NodeTypeResolver\\', __DIR__ . '/../src')
->exclude([__DIR__ . '/../src/Contract']);
->exclude([__DIR__ . '/../src/Contract', __DIR__ . '/../src/Reflection/BetterReflection']);

$services->set(IntermediateSourceLocator::class);
// $services->set(DynamicSourceLocatorProvider::class);

$services->set(TypeAnalyzer::class);
$services->set(FilesFinder::class);
Expand All @@ -48,5 +53,8 @@
$services->set(TypeNodeResolver::class)
->factory([service(PHPStanServicesFactory::class), 'createTypeNodeResolver']);

$services->set(DynamicSourceLocator::class)
->factory([service(PHPStanServicesFactory::class), 'createDynamicSourceLocatorProvider']);

$services->set(NodeConnectingVisitor::class);
};
14 changes: 4 additions & 10 deletions packages/node-type-resolver/config/phpstan/static-reflection.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@ parameters:

services:
- Rector\NodeTypeResolver\Reflection\BetterReflection\RectorBetterReflectionSourceLocatorFactory
- Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator
- Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocator

# basically decorates native PHPStan source locator with a dynamic source locator that is also available in Rector DI
betterReflectionSourceLocator:
class: Roave\BetterReflection\SourceLocator\Type\SourceLocator
factory: @Rector\NodeTypeResolver\Reflection\BetterReflection\RectorBetterReflectionSourceLocatorFactory::create
arguments:
sourceLocator: @defaultBetterReflectionSourceLocator
autowired: false

# see https://github.com/phpstan/phpstan-src/blob/78a9f057d7a1c73cc34af70db406b9392ce0ca3a/conf/config.neon#L1332-L1335
defaultBetterReflectionSourceLocator:
class: Roave\BetterReflection\SourceLocator\Type\SourceLocator
factory: @PHPStan\Reflection\BetterReflection\BetterReflectionSourceLocatorFactory::create
class: _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator
factory: ['@Rector\NodeTypeResolver\Reflection\BetterReflection\RectorBetterReflectionSourceLocatorFactory', 'create']
autowired: false
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PHPStan\PhpDoc\TypeNodeResolver;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Configuration\Option;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocator;
use Symplify\PackageBuilder\Parameter\ParameterProvider;

/**
Expand All @@ -39,19 +40,7 @@ public function __construct(ParameterProvider $parameterProvider)

$existingAdditionalConfigFiles = array_filter($additionalConfigFiles, 'file_exists');

// this allows to statically autoload files from Rector tests
$analysedPathsFromConfig = [];
if (defined('RECTOR_REPOSITORY')) {
$analysedPathsFromConfig[] = sys_get_temp_dir() . '/_temp_fixture_easy_testing';
}

$this->container = $containerFactory->create(
sys_get_temp_dir(),
$existingAdditionalConfigFiles,
[],
[],
$analysedPathsFromConfig
);
$this->container = $containerFactory->create(sys_get_temp_dir(), $existingAdditionalConfigFiles, []);
}

/**
Expand Down Expand Up @@ -117,4 +106,12 @@ public function createTypeNodeResolver(): TypeNodeResolver
{
return $this->container->getByType(TypeNodeResolver::class);
}

/**
* @api
*/
public function createDynamicSourceLocatorProvider(): DynamicSourceLocator
{
return $this->container->getByType(DynamicSourceLocator::class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,34 @@

namespace Rector\NodeTypeResolver\Reflection\BetterReflection;

use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\AggregateSourceLocator;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator;
use PHPStan\Reflection\BetterReflection\BetterReflectionSourceLocatorFactory;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator;

final class RectorBetterReflectionSourceLocatorFactory
{
public function __construct(\Roave\BetterReflection\SourceLocator\Type\SourceLocator $sourceLocator)
/**
* @var BetterReflectionSourceLocatorFactory
*/
private $betterReflectionSourceLocatorFactory;

/**
* @var IntermediateSourceLocator
*/
private $intermediateSourceLocator;

public function __construct(
BetterReflectionSourceLocatorFactory $betterReflectionSourceLocatorFactory,
IntermediateSourceLocator $intermediateSourceLocator
) {
$this->betterReflectionSourceLocatorFactory = $betterReflectionSourceLocatorFactory;
$this->intermediateSourceLocator = $intermediateSourceLocator;
}

public function create(): SourceLocator
{
dump($sourceLocator);
$phpStanSourceLocator = $this->betterReflectionSourceLocatorFactory->create();
return new AggregateSourceLocator([$this->intermediateSourceLocator, $phpStanSourceLocator]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator;

use _HumbugBoxfac515c46e83\Roave\BetterReflection\Identifier\Identifier;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\Identifier\IdentifierType;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\Reflection\Reflection;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\Reflector\Reflector;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocator;

final class IntermediateSourceLocator implements SourceLocator
{
/**
* @var DynamicSourceLocator
*/
private $dynamicSourceLocator;

public function __construct(DynamicSourceLocator $dynamicSourceLocator)
{
$this->dynamicSourceLocator = $dynamicSourceLocator;
}

public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection
{
$sourceLocator = $this->dynamicSourceLocator->provide();

$locatedIdentifier = $sourceLocator->locateIdentifier($reflector, $identifier);
if ($locatedIdentifier instanceof Reflection) {
return $locatedIdentifier;
}

return null;
}

/**
* Find all identifiers of a type
* @return Reflection[]
*/
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array
{
$sourceLocator = $this->dynamicSourceLocator->provide();

$reflections = $sourceLocator->locateIdentifiersByType($reflector, $identifierType);
if ($reflections !== []) {
return $reflections;
}

return [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider;

use _HumbugBoxfac515c46e83\Roave\BetterReflection\Reflector\FunctionReflector;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Ast\Locator;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\AggregateSourceLocator;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\DirectoriesSourceLocator;
use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator;
use PhpParser\Parser;
use PHPStan\DependencyInjection\Container;
use PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher;
use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedSingleFileSourceLocator;
use Symplify\SmartFileSystem\SmartFileInfo;

final class DynamicSourceLocator
{
// /**
// * @var string[]
// */
// private $directories = [];
//
// /**
// * @var Parser
// */
// private $parser;

/**
* @var SmartFileInfo[]
*/
private $fileInfos = [];

// /**
// * @var Container
// */
// private $container;

/**
* @var FileNodesFetcher
*/
private $fileNodesFetcher;

public function __construct(/*Parser $parser , Container $container,*/ FileNodesFetcher $fileNodesFetcher)
{
// $this->parser = $parser;
// $this->container = $container;
$this->fileNodesFetcher = $fileNodesFetcher;
}

// public function addDirectory(string $directory): void
// {
// $this->directories[] = $directory;
// }

public function addFileInfo(SmartFileInfo $fileInfo): void
{
$this->fileInfos[] = $fileInfo;
}

public function provide(): SourceLocator
{
// $locator = new Locator($this->parser, function (): FunctionReflector {
// return $this->container->getService('betterReflectionFunctionReflector');
// });
//
$sourceLocators = [];
// $sourceLocators[] = new DirectoriesSourceLocator($this->directories, $locator);

foreach ($this->fileInfos as $fileInfo) {
$sourceLocators[] = new OptimizedSingleFileSourceLocator($this->fileNodesFetcher, $fileInfo->getRealPath());
}

return new AggregateSourceLocator($sourceLocators);
}
}
5 changes: 5 additions & 0 deletions packages/testing/src/PHPUnit/AbstractRectorTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Stubs\StubLoader;
use Rector\Core\ValueObject\StaticNonPhpFileSuffixes;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocator;
use Rector\Testing\Application\EnabledRectorClassProvider;
use Rector\Testing\Configuration\AllRectorConfigFactory;
use Rector\Testing\Contract\RunnableInterface;
Expand Down Expand Up @@ -180,6 +181,10 @@ protected function doTestFileInfo(SmartFileInfo $fixtureFileInfo, array $extraFi
$nodeScopeResolver = $this->getService(NodeScopeResolver::class);
$nodeScopeResolver->setAnalysedFiles([$inputFileInfo->getRealPath()]);

/** @var DynamicSourceLocator $dynamicDirectoryLocatorProvider */
$dynamicDirectoryLocatorProvider = $this->getService(DynamicSourceLocator::class);
$dynamicDirectoryLocatorProvider->addFileInfo($inputFileInfo);

$expectedFileInfo = $inputFileInfoAndExpectedFileInfo->getExpectedFileInfo();

$this->doTestFileMatchesExpectedContent($inputFileInfo, $expectedFileInfo, $fixtureFileInfo, $extraFileInfos);
Expand Down
4 changes: 0 additions & 4 deletions rules/renaming/src/NodeManipulator/ClassRenamer.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,6 @@ private function refactorNamespace(Namespace_ $namespace, array $oldToNewClasses
$currentName = $this->nodeNameResolver->getName($classLike);
$newClassFullyQualified = $oldToNewClasses[$currentName];

dump($this->reflectionProvider->hasClass($newClassFullyQualified));
dump($newClassFullyQualified);
die;

if ($this->reflectionProvider->hasClass($newClassFullyQualified)) {
return null;
}
Expand Down

0 comments on commit 2f3a909

Please sign in to comment.