phpDocTypeChanger = $phpDocTypeChanger; $this->phpDocNullableTypeHelper = $phpDocNullableTypeHelper; $this->phpDocNestedAnnotationGuard = $phpDocNestedAnnotationGuard; $this->phpVersionProvider = $phpVersionProvider; $this->phpDocInfoAnalyzer = $phpDocInfoAnalyzer; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Add or remove null type from @var phpdoc typehint based on php property type declaration', [new CodeSample(<<<'CODE_SAMPLE' final class SomeClass { /** * @var DateTime[] */ private ?array $dateTimes; } CODE_SAMPLE , <<<'CODE_SAMPLE' final class SomeClass { /** * @var DateTime[]|null */ private ?array $dateTimes; } CODE_SAMPLE )]); } /** * @return array> */ public function getNodeTypes() : array { return [Property::class]; } /** * @param Property $node */ public function refactor(Node $node) : ?Node { if (\count($node->props) !== 1) { return null; } if (!$this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) { return null; } if (!$this->phpDocNestedAnnotationGuard->isPhpDocCommentCorrectlyParsed($node)) { return null; } $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); if (!$this->phpDocInfoAnalyzer->isVarDocAlreadySet($phpDocInfo)) { return null; } if ($node->type === null) { return null; } $phpParserType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($node->type); $varTagValueNode = $phpDocInfo->getVarTagValueNode(); if (!$varTagValueNode instanceof VarTagValueNode) { return null; } if ($varTagValueNode->type === null) { return null; } $docType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($varTagValueNode->type, $node); $updatedPhpDocType = $this->phpDocNullableTypeHelper->resolveUpdatedPhpDocTypeFromPhpDocTypeAndPhpParserType($docType, $phpParserType); if (!$updatedPhpDocType instanceof Type) { return null; } $this->phpDocTypeChanger->changeVarType($phpDocInfo, $updatedPhpDocType); if (!$phpDocInfo->hasChanged()) { return null; } return $node; } }