From 2057d95d8f8e0b6f11117c4b87feb5b881943be0 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 18 Oct 2026 15:17:06 +0200 Subject: [PATCH] make AddProphecyTraitRector idempotent Check existing trait uses structurally before the reflection-based check, so the rule is not fooled by a class reflection that does not yet see the ProphecyTrait added on a previous pass and keeps re-adding it. --- .../Rector/Class_/AddProphecyTraitRector.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rules/PHPUnit100/Rector/Class_/AddProphecyTraitRector.php b/rules/PHPUnit100/Rector/Class_/AddProphecyTraitRector.php index 7c4cff55..fd4b5d46 100644 --- a/rules/PHPUnit100/Rector/Class_/AddProphecyTraitRector.php +++ b/rules/PHPUnit100/Rector/Class_/AddProphecyTraitRector.php @@ -119,6 +119,16 @@ private function shouldSkipClass(Class_ $class): bool return true; } + // structural check first, so the rule stays idempotent even when the class reflection is + // not yet aware of a trait added on a previous pass + foreach ($class->getTraitUses() as $traitUse) { + foreach ($traitUse->traits as $trait) { + if ($this->isName($trait, ProphecyClassName::PROPHECY_TRAIT)) { + return true; + } + } + } + $classReflection = $this->reflectionResolver->resolveClassReflection($class); if (! $classReflection instanceof ClassReflection) { return false;