phpAttributeAnalyzer = $phpAttributeAnalyzer; $this->phpAttributeGroupFactory = $phpAttributeGroupFactory; $this->reflectionResolver = $reflectionResolver; $this->returnTypeChangedClassMethodReferences = [new ClassMethodReference('ArrayAccess', 'getIterator'), new ClassMethodReference('ArrayAccess', 'offsetGet')]; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Add #[\\ReturnTypeWillChange] attribute to configured instanceof class with methods', [new ConfiguredCodeSample(<<<'CODE_SAMPLE' class SomeClass implements ArrayAccess { public function offsetGet($offset) { } } CODE_SAMPLE , <<<'CODE_SAMPLE' class SomeClass implements ArrayAccess { #[\ReturnTypeWillChange] public function offsetGet($offset) { } } CODE_SAMPLE , [new ClassMethodReference('ArrayAccess', 'offsetGet')])]); } /** * @return array> */ public function getNodeTypes() : array { return [Class_::class, Interface_::class]; } /** * @param Class_|Interface_ $node */ public function refactor(Node $node) : ?Node { $hasChanged = \false; $classReflection = $this->reflectionResolver->resolveClassAndAnonymousClass($node); foreach ($node->getMethods() as $classMethod) { if ($this->phpAttributeAnalyzer->hasPhpAttribute($classMethod, AttributeName::RETURN_TYPE_WILL_CHANGE)) { continue; } // the return type is known, no need to add attribute if ($classMethod->returnType !== null) { continue; } foreach ($this->returnTypeChangedClassMethodReferences as $returnTypeChangedClassMethodReference) { if (!$classReflection->isSubclassOf($returnTypeChangedClassMethodReference->getClass())) { continue; } if (!$this->isName($classMethod, $returnTypeChangedClassMethodReference->getMethod())) { continue; } $classMethod->attrGroups[] = $this->phpAttributeGroupFactory->createFromClass(AttributeName::RETURN_TYPE_WILL_CHANGE); $hasChanged = \true; break; } } if ($hasChanged) { return $node; } return null; } /** * @param mixed[] $configuration */ public function configure(array $configuration) : void { Assert::allIsInstanceOf($configuration, ClassMethodReference::class); $this->returnTypeChangedClassMethodReferences = \array_merge($this->returnTypeChangedClassMethodReferences, $configuration); } public function provideMinPhpVersion() : int { return PhpVersionFeature::RETURN_TYPE_WILL_CHANGE_ATTRIBUTE; } }