diff --git a/src/PropertyHooks/NoReturnByReferenceRule.php b/src/PropertyHooks/NoReturnByReferenceRule.php new file mode 100644 index 00000000..c432b6af --- /dev/null +++ b/src/PropertyHooks/NoReturnByReferenceRule.php @@ -0,0 +1,72 @@ + + */ +final class NoReturnByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\PropertyHook::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (false === $node->byRef) { + return []; + } + + $methodName = $node->name->toString(); + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + $message = \sprintf( + 'Property hook %s() in anonymous class returns by reference.', + $methodName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noReturnByReference()->toString()) + ->build(), + ]; + } + + $className = $classReflection->getName(); + + $message = \sprintf( + 'Property hook %s::%s() returns by reference.', + $className, + $methodName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noReturnByReference()->toString()) + ->build(), + ]; + } +} diff --git a/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInClass.php b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInClass.php new file mode 100644 index 00000000..b574958c --- /dev/null +++ b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInClass.php @@ -0,0 +1,19 @@ +foo; + } + } + private $bar { + get { + return $this->bar; + } + } +} diff --git a/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInClassReturningByReference.php b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInClassReturningByReference.php new file mode 100644 index 00000000..3ccf6b5d --- /dev/null +++ b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInClassReturningByReference.php @@ -0,0 +1,19 @@ +foo; + } + } + private $bar { + &get { + return $this->bar; + } + } +} diff --git a/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInTrait.php b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInTrait.php new file mode 100644 index 00000000..fd02fb85 --- /dev/null +++ b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInTrait.php @@ -0,0 +1,19 @@ +foo; + } + } + private $bar { + get { + return $this->bar; + } + } +} diff --git a/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInTraitReturningByReference.php b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInTraitReturningByReference.php new file mode 100644 index 00000000..cb0ebe4c --- /dev/null +++ b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/PropertyHookInTraitReturningByReference.php @@ -0,0 +1,19 @@ +foo; + } + } + private $bar { + &get { + return $this->bar; + } + } +} diff --git a/test/Fixture/PropertyHooks/NoReturnByReferenceRule/script.php b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/script.php new file mode 100644 index 00000000..fd36a81d --- /dev/null +++ b/test/Fixture/PropertyHooks/NoReturnByReferenceRule/script.php @@ -0,0 +1,31 @@ +foo; + } + } + private $bar { + get { + return $this->bar; + } + } +}; + +$bar = new class() { + private $foo { + get { + return $this->foo; + } + } + private $bar { + &get { + return $this->bar; + } + } +}; diff --git a/test/Integration/PropertyHooks/NoReturnByReferenceRuleTest.php b/test/Integration/PropertyHooks/NoReturnByReferenceRuleTest.php new file mode 100644 index 00000000..37facd0f --- /dev/null +++ b/test/Integration/PropertyHooks/NoReturnByReferenceRuleTest.php @@ -0,0 +1,56 @@ + + */ +final class NoReturnByReferenceRuleTest extends Testing\RuleTestCase +{ + use Test\Util\Helper; + + public function testNoReturnByReferenceRule(): void + { + $this->analyse( + self::phpFilesIn(__DIR__ . '/../../Fixture/PropertyHooks/NoReturnByReferenceRule'), + [ + [ + \sprintf( + 'Property hook %s::foo() returns by reference.', + Test\Fixture\PropertyHooks\NoReturnByReferenceRule\PropertyHookInClassReturningByReference::class, + ), + 15, + ], + [ + 'Property hook foo() in anonymous class returns by reference.', + 27, + ], + ], + ); + } + + protected function getRule(): Rules\Rule + { + return new PropertyHooks\NoReturnByReferenceRule(); + } +}