trustedClassMethodPropertyTypeInferer = $trustedClassMethodPropertyTypeInferer; $this->staticTypeMapper = $staticTypeMapper; $this->phpDocInfoFactory = $phpDocInfoFactory; $this->docBlockUpdater = $docBlockUpdater; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Add strict typed property based on setUp() strict typed assigns in TestCase', [new CodeSample(<<<'CODE_SAMPLE' use PHPUnit\Framework\TestCase; final class SomeClass extends TestCase { private $value; public function setUp() { $this->value = 1000; } } CODE_SAMPLE , <<<'CODE_SAMPLE' use PHPUnit\Framework\TestCase; final class SomeClass extends TestCase { private int $value; public function setUp() { $this->value = 1000; } } CODE_SAMPLE )]); } /** * @return array> */ public function getNodeTypes() : array { return [Class_::class]; } /** * @param Class_ $node */ public function refactor(Node $node) : ?Node { $setUpClassMethod = $node->getMethod(MethodName::SET_UP); if (!$setUpClassMethod instanceof ClassMethod) { return null; } $hasChanged = \false; foreach ($node->getProperties() as $property) { // type is already set if ($property->type !== null) { continue; } // is not private? we cannot be sure about other usage if (!$property->isPrivate()) { continue; } $propertyType = $this->trustedClassMethodPropertyTypeInferer->inferProperty($node, $property, $setUpClassMethod); $propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($propertyType, TypeKind::PROPERTY); if (!$propertyTypeNode instanceof Node) { continue; } if ($propertyType instanceof ObjectType && $propertyType->getClassName() === 'PHPUnit\\Framework\\MockObject\\MockObject') { $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property); $varTag = $phpDocInfo->getVarTagValueNode(); $varType = $phpDocInfo->getVarType(); if ($varTag instanceof VarTagValueNode && $varType instanceof ObjectType && $varType->getClassName() !== 'PHPUnit\\Framework\\MockObject\\MockObject') { $varTag->type = new IntersectionTypeNode([new FullyQualifiedIdentifierTypeNode($propertyType->getClassName()), new FullyQualifiedIdentifierTypeNode($varType->getClassName())]); $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($property); } } $property->type = $propertyTypeNode; $hasChanged = \true; } if ($hasChanged) { return $node; } return null; } public function provideMinPhpVersion() : int { return PhpVersionFeature::TYPED_PROPERTIES; } }