|
6 | 6 | use PhpParser\Node; |
7 | 7 | use PHPStan\Analyser\Scope; |
8 | 8 | use PHPStan\DependencyInjection\RegisteredRule; |
| 9 | +use PHPStan\Node\Expr\CloneReinitializationExpr; |
9 | 10 | use PHPStan\Node\Expr\SetOffsetValueTypeExpr; |
10 | 11 | use PHPStan\Node\Expr\UnsetOffsetExpr; |
11 | 12 | use PHPStan\Node\PropertyAssignNode; |
@@ -96,15 +97,26 @@ public function processNode(Node $node, Scope $scope): array |
96 | 97 | throw new ShouldNotHappenException(); |
97 | 98 | } |
98 | 99 |
|
| 100 | + $methodName = $scopeMethod->getName(); |
| 101 | + $inClone = $this->phpVersion->supportsReadonlyPropertyReinitializationOnClone() && strtolower($methodName) === '__clone'; |
99 | 102 | if ( |
100 | | - in_array($scopeMethod->getName(), $this->constructorsHelper->getConstructors($scopeClassReflection), true) |
101 | | - || strtolower($scopeMethod->getName()) === '__unserialize' |
| 103 | + in_array($methodName, $this->constructorsHelper->getConstructors($scopeClassReflection), true) |
| 104 | + || strtolower($methodName) === '__unserialize' |
| 105 | + || $inClone |
102 | 106 | ) { |
103 | 107 | if (TypeUtils::findThisType($scope->getType($propertyFetch->var)) === null) { |
104 | 108 | $errors[] = RuleErrorBuilder::message(sprintf('Readonly property %s::$%s is not assigned on $this.', $declaringClass->getDisplayName(), $propertyReflection->getName())) |
105 | 109 | ->line($propertyFetch->name->getStartLine()) |
106 | 110 | ->identifier('property.readOnlyAssignNotOnThis') |
107 | 111 | ->build(); |
| 112 | + } elseif ( |
| 113 | + $inClone |
| 114 | + && !$scope->hasExpressionType(new CloneReinitializationExpr($propertyReflection->getName()))->no() |
| 115 | + ) { |
| 116 | + $errors[] = RuleErrorBuilder::message(sprintf('Readonly property %s::$%s is already assigned.', $declaringClass->getDisplayName(), $propertyReflection->getName())) |
| 117 | + ->line($propertyFetch->name->getStartLine()) |
| 118 | + ->identifier('assign.readOnlyProperty') |
| 119 | + ->build(); |
108 | 120 | } |
109 | 121 |
|
110 | 122 | continue; |
|
0 commit comments