diff --git a/rector.php b/rector.php index 3211c044..58657fc0 100644 --- a/rector.php +++ b/rector.php @@ -24,5 +24,6 @@ __DIR__ . '/src/Rules/Symfony/ConstraintMustHaveAttributeRule.php', __DIR__ . '/tests/Naming/ClassToSuffixResolverTest.php', __DIR__ . '/src/Doctrine/DoctrineEntityDocumentAnalyser.php', + __DIR__ . '/src/Collector/NewWithFollowingSettersCollector.php', ], ]); diff --git a/src/Collector/NewWithFollowingSettersCollector.php b/src/Collector/NewWithFollowingSettersCollector.php index 901b2b3d..22b87ca5 100644 --- a/src/Collector/NewWithFollowingSettersCollector.php +++ b/src/Collector/NewWithFollowingSettersCollector.php @@ -24,6 +24,7 @@ use PhpParser\NodeFinder; use PHPStan\Analyser\Scope; use PHPStan\Collectors\Collector; +use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use Symfony\Component\HttpKernel\Kernel; use Webmozart\Assert\Assert; @@ -159,11 +160,24 @@ private function shouldSkipClass(string $className): bool return true; } - // skip Doctrine entities - $fileContents = file_get_contents($classReflection->getFileName()); + // skip Doctrine entities, they are usually set/get magically + return $this->isDoctrineEntity($classReflection); + } + + private function isDoctrineEntity(ClassReflection $classReflection): bool + { + // #[ORM\Entity] attribute + foreach ($classReflection->getNativeReflection()->getAttributes() as $attributeReflection) { + if ($attributeReflection->getName() === 'Doctrine\ORM\Mapping\Entity') { + return true; + } + } + + // @ORM\Entity annotation fallback + $fileContents = file_get_contents((string) $classReflection->getFileName()); Assert::string($fileContents); - return str_contains($fileContents, '@ORM\Entity') || str_starts_with($fileContents, '#[Entity]'); + return str_contains($fileContents, '@ORM\Entity'); } /** diff --git a/tests/Rules/NewOverSettersRule/Fixture/SkipAttributeEntity.php b/tests/Rules/NewOverSettersRule/Fixture/SkipAttributeEntity.php new file mode 100644 index 00000000..0df0daa4 --- /dev/null +++ b/tests/Rules/NewOverSettersRule/Fixture/SkipAttributeEntity.php @@ -0,0 +1,24 @@ +setName('John'); + $alwaysSetters->setAge(25); + } + + public function second() + { + $alwaysSetters = new SomeAttributeEntity(); + $alwaysSetters->setName('Doe'); + $alwaysSetters->setAge(35); + } +} diff --git a/tests/Rules/NewOverSettersRule/NewOverSettersRuleTest.php b/tests/Rules/NewOverSettersRule/NewOverSettersRuleTest.php index c258a16d..ce3ed092 100644 --- a/tests/Rules/NewOverSettersRule/NewOverSettersRuleTest.php +++ b/tests/Rules/NewOverSettersRule/NewOverSettersRuleTest.php @@ -50,6 +50,7 @@ public static function provideData(): Iterator yield [__DIR__ . '/Fixture/SkipSomeKernel.php', []]; yield [__DIR__ . '/Fixture/SkipEntity.php', []]; + yield [__DIR__ . '/Fixture/SkipAttributeEntity.php', []]; yield [__DIR__ . '/Fixture/SkipNotSetterCall.php', []]; yield [__DIR__ . '/Fixture/SkipNoArgSetters.php', []]; } diff --git a/tests/Rules/NewOverSettersRule/Source/SomeAttributeEntity.php b/tests/Rules/NewOverSettersRule/Source/SomeAttributeEntity.php new file mode 100644 index 00000000..47f7ff2e --- /dev/null +++ b/tests/Rules/NewOverSettersRule/Source/SomeAttributeEntity.php @@ -0,0 +1,17 @@ +