classMethodReturnTypeOverrideGuard = $classMethodReturnTypeOverrideGuard; $this->reflectionResolver = $reflectionResolver; $this->returnTypeInferer = $returnTypeInferer; $this->phpVersionProvider = $phpVersionProvider; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Add return type from strict return $this', [new CodeSample(<<<'CODE_SAMPLE' final class SomeClass { public function run() { return $this; } } CODE_SAMPLE , <<<'CODE_SAMPLE' final class SomeClass { public function run(): self { return $this; } } CODE_SAMPLE )]); } /** * @return array> */ public function getNodeTypes() : array { return [ClassMethod::class]; } public function provideMinPhpVersion() : int { return PhpVersionFeature::HAS_RETURN_TYPE; } /** * @param ClassMethod $node */ public function refactorWithScope(Node $node, Scope $scope) : ?Node { // already typed → skip if ($node->returnType instanceof Node) { return null; } if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) { return null; } $classReflection = $this->reflectionResolver->resolveClassReflection($node); if (!$classReflection instanceof ClassReflection) { return null; } $returnType = $this->returnTypeInferer->inferFunctionLike($node); if ($returnType instanceof StaticType && $returnType->getStaticObjectType()->getClassName() === $classReflection->getName()) { return $this->processAddReturnSelfOrStatic($node, $classReflection); } if ($returnType instanceof ObjectType && $returnType->getClassName() === $classReflection->getName()) { $node->returnType = new Name('self'); return $node; } if (!$returnType instanceof ThisType) { return null; } return $this->processAddReturnSelfOrStatic($node, $classReflection); } private function processAddReturnSelfOrStatic(ClassMethod $classMethod, ClassReflection $classReflection) : ClassMethod { $classMethod->returnType = $this->shouldSelf($classReflection) ? new Name('self') : new Name('static'); return $classMethod; } private function shouldSelf(ClassReflection $classReflection) : bool { if ($classReflection->isAnonymous()) { return \true; } if ($classReflection->isFinalByKeyword()) { return \true; } return !$this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::STATIC_RETURN_TYPE); } }