Skip to content

Commit

Permalink
[DX] Make use of Laravel container in few tests - step #1 (#4672)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba authored Aug 6, 2023
1 parent 3dbaeb0 commit 2ffa009
Show file tree
Hide file tree
Showing 25 changed files with 369 additions and 205 deletions.
11 changes: 9 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
"bin/rector"
],
"license": "MIT",
"keywords": ["refactoring", "automation", "migration"],
"keywords": [
"refactoring",
"automation",
"migration"
],
"homepage": "https://getrector.org",
"require": {
"php": "^8.1",
Expand Down Expand Up @@ -133,6 +137,9 @@
},
"extra": {
"patches": {
"illuminate/container": [
"patches/illuminate-container-container-php.patch"
],
"nikic/php-parser": [
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-expr-closure-php.patch",
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-stmt-finally-php.patch",
Expand Down Expand Up @@ -171,4 +178,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
7 changes: 3 additions & 4 deletions packages-tests/BetterPhpDocParser/PhpDocNodeMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use Rector\BetterPhpDocParser\PhpDocNodeMapper;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Rector\Testing\PHPUnit\AbstractLazyTestCase;

final class PhpDocNodeMapperTest extends AbstractTestCase
final class PhpDocNodeMapperTest extends AbstractLazyTestCase
{
private PhpDocNodeMapper $phpDocNodeMapper;

protected function setUp(): void
{
$this->boot();
$this->phpDocNodeMapper = $this->getService(PhpDocNodeMapper::class);
$this->phpDocNodeMapper = $this->make(PhpDocNodeMapper::class);
}

public function testParamTag(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ public function testResolvesClass(string $filePath): void
$value = $varTagValueNode->type->__toString();
$propertyName = strtolower($this->nodeNameResolver->getName($property));

$result = $this->classAnnotationMatcher->resolveTagToKnownFullyQualifiedName($value, $property);
$result = $this->classAnnotationMatcher->resolveTagFullyQualifiedName($value, $property);
if (str_starts_with($propertyName, 'unknown')) {
$this->assertNull($result);
$this->assertStringContainsString('Unknown', $result);
} elseif (str_contains($propertyName, 'aliased')) {
$unaliasedClass = str_replace('Aliased', '', $value);
$this->assertStringEndsWith($unaliasedClass, $result ?? '');
$this->assertStringEndsWith($unaliasedClass, $result);
} elseif (str_starts_with($propertyName, 'known')) {
$this->assertStringEndsWith($value, $result ?? '');
$this->assertStringEndsWith($value, $result);
} else {
throw new ShouldNotHappenException('All Variables should start with "known" or "unknown"!');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Use_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
Expand All @@ -32,24 +31,8 @@ public function __construct(
) {
}

/**
* @api doctrine
*/
public function resolveTagToKnownFullyQualifiedName(string $tag, Property $property): ?string
public function resolveTagFullyQualifiedName(string $tag, Node $node): string
{
return $this->_resolveTagFullyQualifiedName($tag, $property, true);
}

public function resolveTagFullyQualifiedName(string $tag, Node $node): ?string
{
return $this->_resolveTagFullyQualifiedName($tag, $node, false);
}

private function _resolveTagFullyQualifiedName(
string $tag,
Node $node,
bool $returnNullOnUnknownClass
): ?string {
$uniqueHash = $tag . spl_object_hash($node);
if (isset($this->fullyQualifiedNameByHash[$uniqueHash])) {
return $this->fullyQualifiedNameByHash[$uniqueHash];
Expand All @@ -58,13 +41,9 @@ private function _resolveTagFullyQualifiedName(
$tag = ltrim($tag, '@');

$uses = $this->useImportsResolver->resolve();
$fullyQualifiedClass = $this->resolveFullyQualifiedClass($uses, $node, $tag, $returnNullOnUnknownClass);
$fullyQualifiedClass = $this->resolveFullyQualifiedClass($uses, $node, $tag, false);

if ($fullyQualifiedClass === null) {
if ($returnNullOnUnknownClass) {
return null;
}

$fullyQualifiedClass = $tag;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ private function transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes(
}

// known doc tag to annotation class
$fullyQualifiedAnnotationClass = (string) $this->classAnnotationMatcher->resolveTagFullyQualifiedName(
$fullyQualifiedAnnotationClass = $this->classAnnotationMatcher->resolveTagFullyQualifiedName(
$phpDocChildNode->name,
$currentPhpNode
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
use PHPStan\Analyser\NodeScopeResolver;
use PHPStan\Analyser\ScopeContext;
use PHPStan\Node\UnreachableStatementNode;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeCombinator;
Expand Down Expand Up @@ -222,28 +221,20 @@ public function processNodes(

$traitScope = clone $mutatingScope;

$scopeContext = $this->privatesAccessor->getPrivatePropertyOfClass(
$traitScope,
self::CONTEXT,
ScopeContext::class
);
/** @var ScopeContext $scopeContext */
$scopeContext = $this->privatesAccessor->getPrivateProperty($traitScope, self::CONTEXT);

$traitContext = clone $scopeContext;

// before entering the class/trait again, we have to tell scope no class was set, otherwise it crashes
$this->privatesAccessor->setPrivatePropertyOfClass(
$this->privatesAccessor->setPrivateProperty(
$traitContext,
'classReflection',
$traitClassReflection,
ClassReflection::class
);
$this->privatesAccessor->setPrivatePropertyOfClass(
$traitScope,
self::CONTEXT,
$traitContext,
ScopeContext::class
);

$this->privatesAccessor->setPrivateProperty($traitScope, self::CONTEXT, $traitContext);

$node->setAttribute(AttributeKey::SCOPE, $traitScope);
$this->nodeScopeResolver->processNodes($node->stmts, $traitScope, $nodeCallback);
$this->decorateTraitAttrGroups($node, $traitScope);
Expand Down
9 changes: 5 additions & 4 deletions packages/StaticTypeMapper/Naming/NameScopeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,26 @@ final class NameScopeFactory

private PhpDocInfoFactory $phpDocInfoFactory;

private UseImportsResolver $useImportsResolver;

private ReflectionResolver $reflectionResolver;

private ClassLikeAstResolver $classLikeAstResolver;

public function __construct(
private readonly UseImportsResolver $useImportsResolver,
) {
}

// This is needed to avoid circular references

#[Required]
public function autowire(
PhpDocInfoFactory $phpDocInfoFactory,
StaticTypeMapper $staticTypeMapper,
UseImportsResolver $useImportsResolver,
ReflectionResolver $reflectionResolver,
ClassLikeAstResolver $classLikeAstResolver
): void {
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->staticTypeMapper = $staticTypeMapper;
$this->useImportsResolver = $useImportsResolver;
$this->reflectionResolver = $reflectionResolver;
$this->classLikeAstResolver = $classLikeAstResolver;
}
Expand Down
8 changes: 6 additions & 2 deletions packages/Testing/PHPUnit/AbstractLazyTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Rector\Testing\PHPUnit;

use Illuminate\Container\Container;
use PHPUnit\Framework\TestCase;
use Rector\Core\DependencyInjection\LazyContainerFactory;

abstract class AbstractLazyTestCase extends TestCase
{
Expand All @@ -16,7 +16,11 @@ abstract class AbstractLazyTestCase extends TestCase
*/
protected function make(string $class): object
{
$container = new Container();
// @todo cache container

$lazyContainerFactory = new LazyContainerFactory();
$container = $lazyContainerFactory->create();

return $container->make($class);
}
}
11 changes: 11 additions & 0 deletions patches/illuminate-container-container-php.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- /dev/null
+++ ../Container.php
@@ -805,7 +805,7 @@
// If the requested type is registered as a singleton we'll want to cache off
// the instances in "memory" so we can return it later without creating an
// entirely new instance of an object on each subsequent request for it.
- if ($this->isShared($abstract) && ! $needsContextualBuild) {
+ if (! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}

13 changes: 13 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
includes:
- vendor/symplify/phpstan-rules/config/symplify-rules.neon

services:
# makes $container->make() generic type
- Rector\Utils\PHPStan\ClassConstFetchReturnTypeResolver
-
class: Rector\Utils\PHPStan\TypeExtension\ContainerMakeReturnTypeExtension
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension

parameters:
reportUnmatchedIgnoredErrors: false

Expand Down Expand Up @@ -669,3 +677,8 @@ parameters:
-
message: '#Public method "Rector\\Core\\DependencyInjection\\RectorContainerFactory\:\:createFromBootstrapConfigs\(\)" is never used#'
path: src/DependencyInjection/RectorContainerFactory.php

# will be more generic later
-
message: '#Parameters should use "Symfony\\Component\\Console\\Application\|string\|callable" types as the only types passed to this method#'
path: src/Util/Reflection/PrivatesAccessor.php
15 changes: 3 additions & 12 deletions rules/TypeDeclaration/TypeNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,9 @@ public function normalizeArrayTypeAndArrayNever(Type $type): Type
assert($traversedType instanceof ConstantArrayType);

// not sure why, but with direct new node everything gets nulled to MixedType
$this->privatesAccessor->setPrivatePropertyOfClass(
$traversedType,
'keyType',
new MixedType(),
Type::class
);
$this->privatesAccessor->setPrivatePropertyOfClass(
$traversedType,
'itemType',
new MixedType(),
Type::class
);
$this->privatesAccessor->setPrivateProperty($traversedType, 'keyType', new MixedType());

$this->privatesAccessor->setPrivateProperty($traversedType, 'itemType', new MixedType());

return $traversedType;
}
Expand Down
Loading

0 comments on commit 2ffa009

Please sign in to comment.