Skip to content

Commit

Permalink
Merge pull request #188 from NaokiTsuchiya/fix/parent-intercept
Browse files Browse the repository at this point in the history
Fix wrong compiled method of parent
  • Loading branch information
koriym authored Feb 21, 2022
2 parents f6076c0 + 151e3b9 commit 7c5bcca
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/AopClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function __invoke(CodeVisitor $visitor, ReflectionClass $sourceClass, Bin
{
assert($visitor->class instanceof Class_);
$methods = $this->codeGenMethod->getMethods($sourceClass, $bind, $visitor);
$propStms = ($this->aopProps)($sourceClass);
$propStms = ($this->aopProps)($sourceClass, $visitor);
$classStm = $visitor->class;
$newClassName = ($this->aopClassName)((string) $visitor->class->name, $bind->toString(''));
$classStm->name = new Identifier($newClassName);
Expand Down
12 changes: 7 additions & 5 deletions src/AopProps.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(BuilderFactory $factory)
*
* @return Property[]
*/
public function __invoke(ReflectionClass $class): array
public function __invoke(ReflectionClass $class, CodeVisitor $visitor): array
{
$pros = [];
$pros[] = $this->factory
Expand All @@ -47,12 +47,12 @@ public function __invoke(ReflectionClass $class): array

$pros[] = $this->factory
->property('methodAnnotations')
->setDefault($this->getMethodAnnotations($class))
->setDefault($this->getMethodAnnotations($class, $visitor))
->makePublic()
->getNode();
$pros[] = $this->factory
->property('classAnnotations')
->setDefault($this->getClassAnnotation($class))
->setDefault($this->getClassAnnotation($class, $visitor))
->makePublic()
->getNode();
$pros[] = $this->factory
Expand All @@ -67,7 +67,7 @@ public function __invoke(ReflectionClass $class): array
/**
* @param ReflectionClass<object> $class
*/
private function getMethodAnnotations(ReflectionClass $class): string
private function getMethodAnnotations(ReflectionClass $class, CodeVisitor $visitor): string
{
$methodsAnnotation = [];
$methods = $class->getMethods();
Expand All @@ -78,6 +78,7 @@ private function getMethodAnnotations(ReflectionClass $class): string
}

$methodsAnnotation[$method->name] = $annotations;
$visitor->addUses($annotations);
}

return serialize($methodsAnnotation);
Expand All @@ -88,9 +89,10 @@ private function getMethodAnnotations(ReflectionClass $class): string
*
* @template T of object
*/
private function getClassAnnotation(ReflectionClass $class): string
private function getClassAnnotation(ReflectionClass $class, CodeVisitor $visitor): string
{
$classAnnotations = $this->reader->getClassAnnotations($class);
$visitor->addUses($classAnnotations);

return serialize($classAnnotations);
}
Expand Down
21 changes: 20 additions & 1 deletion src/CodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@
namespace Ray\Aop;

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Declare_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\NodeVisitorAbstract;
use Ray\Aop\Exception\MultipleClassInOneFileException;

use function get_class;
use function implode;

final class CodeVisitor extends NodeVisitorAbstract
{
/** @var ?Namespace_ */
Expand Down Expand Up @@ -42,7 +47,7 @@ public function enterNode(Node $node)
}

if ($node instanceof Use_) {
$this->use[] = $node;
$this->addUse($node);

return null;
}
Expand Down Expand Up @@ -84,4 +89,18 @@ private function enterNodeClass(Node $node)

return null;
}

/** @param array<object> $annotations */
public function addUses(array $annotations): void
{
foreach ($annotations as $annotation) {
$this->addUse(new Use_([new UseUse(new Name(get_class($annotation)))]));
}
}

private function addUse(Use_ $use): void
{
$index = implode('\\', $use->uses[0]->name->parts);
$this->use[$index] = $use;
}
}
3 changes: 3 additions & 0 deletions src/VisitorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Ray\Aop;

use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\Parser;
use Ray\Aop\Exception\InvalidSourceClassException;
use ReflectionClass;
Expand All @@ -31,7 +32,9 @@ public function __construct(Parser $parser)
public function __invoke(ReflectionClass $class): CodeVisitor
{
$traverser = new NodeTraverser();
$nameResolver = new NameResolver();
$visitor = new CodeVisitor();
$traverser->addVisitor($nameResolver);
$traverser->addVisitor($visitor);
$fileName = $class->getFileName();
if (is_bool($fileName)) {
Expand Down
22 changes: 20 additions & 2 deletions tests/CodeGenPhp71Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function testTypedParam(): void
$bind = new Bind();
$bind->bindInterceptors('typed', []);
$code = $this->codeGen->generate(new ReflectionClass(FakePhp71NullableClass::class), $bind);
$expected = 'public function typed(SplObjectStorage $storage)';
$expected = 'public function typed(\SplObjectStorage $storage) : \SplObjectStorage';
$this->assertStringContainsString($expected, $code->code);
}

Expand All @@ -86,7 +86,25 @@ public function testUseTyped(): void
$bind = new Bind();
$bind->bindInterceptors('useTyped', []);
$code = $this->codeGen->generate(new ReflectionClass(FakePhp71NullableClass::class), $bind);
$expected = 'public function useTyped(CodeGen $codeGen)';
$expected = 'public function useTyped(\Ray\Aop\CodeGen $codeGen)';
$this->assertStringContainsString($expected, $code->code);
}

public function testAttribute(): void
{
$bind = new Bind();
$bind->bindInterceptors('attributed', []);
$code = $this->codeGen->generate(new ReflectionClass(FakePhp71NullableClass::class), $bind);
$expected = '#[\Ray\Aop\Annotation\FakeMarker3]';
$this->assertStringContainsString($expected, $code->code);
}

public function testUseAnnotation(): void
{
$bind = new Bind();
$bind->bindInterceptors('attributed', []);
$code = $this->codeGen->generate(new ReflectionClass(FakePhp71NullableClass::class), $bind);
$expected = "use Ray\\Aop\\Annotation\\FakeMarker3;\n";
$this->assertStringContainsString($expected, $code->code);
}
}
12 changes: 12 additions & 0 deletions tests/CompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Ray\Aop;

use ArrayIterator;
use Doctrine\Common\Annotations\AnnotationReader;
use FakeGlobalEmptyNamespaced;
use FakeGlobalNamespaced;
Expand Down Expand Up @@ -130,6 +131,17 @@ public function testParentMethodIntercept(): void
$this->assertSame(2, $result);
}

public function testTypedParentMethodIntercept(): void
{
$bind = (new Bind())->bindInterceptors('passIterator', [new NullInterceptor()]);
$mock = $this->compiler->newInstance(FakeTypedMockChild::class, [], $bind);
assert($mock instanceof FakeTypedMockChild);
assert(property_exists($mock, 'bindings'));
$mock->bindings = $bind->getBindings();
$result = $mock->passIterator(new ArrayIterator());
$this->assertInstanceOf(ArrayIterator::class, $result);
}

public function testParentOfParentMethodIntercept(): void
{
$mock = $this->compiler->newInstance(FakeMockChildChild::class, [], $this->bind);
Expand Down
10 changes: 9 additions & 1 deletion tests/Fake/FakePhp71NullableClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Ray\Aop;

use Composer\Autoload;
use Ray\Aop\Annotation\FakeMarker3;
use SplObjectStorage;

class FakePhp71NullableClass
Expand Down Expand Up @@ -34,11 +35,18 @@ public function variadicParam(int ...$ids)
return $ids[0];
}

public function typed(SplObjectStorage $storage)
public function typed(SplObjectStorage $storage): SplObjectStorage
{
return $storage;
}

public function useTyped(CodeGen $codeGen)
{
}

/** @FakeMarker3 */
#[FakeMarker3]
public function attributed()
{
}
}
19 changes: 19 additions & 0 deletions tests/Fake/FakeTypedMock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Ray\Aop;

use ArrayIterator;
use Ray\Aop\Annotation\FakeMarker3;
use Traversable;

class FakeTypedMock
{
/** @FakeMarker3 */
#[FakeMarker3]
public function passIterator(ArrayIterator $iterator): Traversable
{
return $iterator;
}
}
9 changes: 9 additions & 0 deletions tests/Fake/FakeTypedMockChild.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Ray\Aop;

class FakeTypedMockChild extends FakeTypedMock
{
}

0 comments on commit 7c5bcca

Please sign in to comment.