classMethodReturnTypeOverrideGuard = $classMethodReturnTypeOverrideGuard; $this->returnTypeInferer = $returnTypeInferer; $this->betterNodeFinder = $betterNodeFinder; $this->staticTypeMapper = $staticTypeMapper; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Add method return type based on strict ternary values', [new CodeSample(<<<'CODE_SAMPLE' final class SomeClass { public function getValue($number) { return $number ? 100 : 500; } } CODE_SAMPLE , <<<'CODE_SAMPLE' final class SomeClass { public function getValue($number): int { return $number ? 100 : 500; } } CODE_SAMPLE )]); } /** * @return array> */ public function getNodeTypes() : array { return [ClassMethod::class, Function_::class, Closure::class]; } /** * @param ClassMethod|Function_|Closure $node */ public function refactorWithScope(Node $node, Scope $scope) : ?Node { if ($this->shouldSkip($node, $scope)) { return null; } if ($node->stmts === null) { return null; } $returns = $this->betterNodeFinder->findInstancesOfInFunctionLikeScoped($node, Return_::class); if (\count($returns) !== 1) { return null; } $return = $returns[0]; if (!$return->expr instanceof Ternary) { return null; } $ternary = $return->expr; $returnScope = $return->expr->getAttribute(AttributeKey::SCOPE); if (!$returnScope instanceof Scope) { return null; } $nativeTernaryType = $returnScope->getNativeType($ternary); if ($nativeTernaryType instanceof MixedType) { return null; } $ternaryType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($ternary); $returnTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($ternaryType, TypeKind::RETURN); if (!$returnTypeNode instanceof Node) { return null; } $node->returnType = $returnTypeNode; return $node; } public function provideMinPhpVersion() : int { return PhpVersionFeature::SCALAR_TYPES; } /** * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node */ private function shouldSkip($node, Scope $scope) : bool { if ($node->returnType !== null) { return \true; } $returnType = $this->returnTypeInferer->inferFunctionLike($node); $returnType = TypeCombinator::removeNull($returnType); if ($returnType instanceof UnionType) { return \true; } return $node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope); } }