|
41 | 41 | use function array_keys; |
42 | 42 | use function array_map; |
43 | 43 | use function array_merge; |
| 44 | +use function array_slice; |
44 | 45 | use function count; |
| 46 | +use function implode; |
45 | 47 | use function in_array; |
46 | 48 | use function is_string; |
47 | 49 | use function sprintf; |
@@ -183,17 +185,23 @@ public function checkAnonymousFunction( |
183 | 185 | ->build(); |
184 | 186 | continue; |
185 | 187 | } |
186 | | - |
187 | | - $errors = array_merge( |
188 | | - $errors, |
189 | | - $this->classCheck->checkClassNames($scope, [ |
190 | | - new ClassNameNodePair($class, $param->type), |
191 | | - ], ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE, [ |
192 | | - 'parameterName' => $param->var->name, |
193 | | - 'isInAnonymousFunction' => true, |
194 | | - ]), $this->checkClassCaseSensitivity), |
195 | | - ); |
196 | 188 | } |
| 189 | + |
| 190 | + $anonParamOriginalCasePairs = $this->getOriginalClassNamePairsFromTypeNode($param->type); |
| 191 | + |
| 192 | + $errors = array_merge( |
| 193 | + $errors, |
| 194 | + $this->classCheck->checkClassNames($scope, array_map(static function (string $class) use ($param, $anonParamOriginalCasePairs): ClassNameNodePair { |
| 195 | + $lowerClass = strtolower($class); |
| 196 | + if (isset($anonParamOriginalCasePairs[$lowerClass])) { |
| 197 | + return $anonParamOriginalCasePairs[$lowerClass]; |
| 198 | + } |
| 199 | + return new ClassNameNodePair($class, $param->type); |
| 200 | + }, $type->getReferencedClasses()), ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE, [ |
| 201 | + 'parameterName' => $param->var->name, |
| 202 | + 'isInAnonymousFunction' => true, |
| 203 | + ]), $this->checkClassCaseSensitivity), |
| 204 | + ); |
197 | 205 | } |
198 | 206 |
|
199 | 207 | if ($this->phpVersion->deprecatesRequiredParameterAfterOptional()) { |
@@ -260,17 +268,23 @@ public function checkAnonymousFunction( |
260 | 268 | ->build(); |
261 | 269 | continue; |
262 | 270 | } |
263 | | - |
264 | | - $errors = array_merge( |
265 | | - $errors, |
266 | | - $this->classCheck->checkClassNames($scope, [ |
267 | | - new ClassNameNodePair($returnTypeClass, $returnTypeNode), |
268 | | - ], ClassNameUsageLocation::from(ClassNameUsageLocation::RETURN_TYPE, [ |
269 | | - 'isInAnonymousFunction' => true, |
270 | | - ]), $this->checkClassCaseSensitivity), |
271 | | - ); |
272 | 271 | } |
273 | 272 |
|
| 273 | + $anonReturnOriginalCasePairs = $this->getOriginalClassNamePairsFromTypeNode($returnTypeNode); |
| 274 | + |
| 275 | + $errors = array_merge( |
| 276 | + $errors, |
| 277 | + $this->classCheck->checkClassNames($scope, array_map(static function (string $class) use ($returnTypeNode, $anonReturnOriginalCasePairs): ClassNameNodePair { |
| 278 | + $lowerClass = strtolower($class); |
| 279 | + if (isset($anonReturnOriginalCasePairs[$lowerClass])) { |
| 280 | + return $anonReturnOriginalCasePairs[$lowerClass]; |
| 281 | + } |
| 282 | + return new ClassNameNodePair($class, $returnTypeNode); |
| 283 | + }, $returnType->getReferencedClasses()), ClassNameUsageLocation::from(ClassNameUsageLocation::RETURN_TYPE, [ |
| 284 | + 'isInAnonymousFunction' => true, |
| 285 | + ]), $this->checkClassCaseSensitivity), |
| 286 | + ); |
| 287 | + |
274 | 288 | return $errors; |
275 | 289 | } |
276 | 290 |
|
@@ -469,11 +483,19 @@ private function checkParametersAcceptor( |
469 | 483 | $locationData['function'] = $parametersAcceptor; |
470 | 484 | } |
471 | 485 |
|
| 486 | + $originalCasePairs = $this->getOriginalClassNamePairsFromTypeNode($parameterNodeCallback()->type); |
| 487 | + |
472 | 488 | $errors = array_merge( |
473 | 489 | $errors, |
474 | 490 | $this->classCheck->checkClassNames( |
475 | 491 | $scope, |
476 | | - array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $parameterNodeCallback()), $referencedClasses), |
| 492 | + array_map(static function (string $class) use ($parameterNodeCallback, $originalCasePairs): ClassNameNodePair { |
| 493 | + $lowerClass = strtolower($class); |
| 494 | + if (isset($originalCasePairs[$lowerClass])) { |
| 495 | + return $originalCasePairs[$lowerClass]; |
| 496 | + } |
| 497 | + return new ClassNameNodePair($class, $parameterNodeCallback()); |
| 498 | + }, $referencedClasses), |
477 | 499 | ClassNameUsageLocation::from(ClassNameUsageLocation::PARAMETER_TYPE, $locationData), |
478 | 500 | $this->checkClassCaseSensitivity, |
479 | 501 | ), |
@@ -541,11 +563,19 @@ private function checkParametersAcceptor( |
541 | 563 | $locationData['function'] = $parametersAcceptor; |
542 | 564 | } |
543 | 565 |
|
| 566 | + $returnOriginalCasePairs = $this->getOriginalClassNamePairsFromTypeNode($functionNode->getReturnType()); |
| 567 | + |
544 | 568 | $errors = array_merge( |
545 | 569 | $errors, |
546 | 570 | $this->classCheck->checkClassNames( |
547 | 571 | $scope, |
548 | | - array_map(static fn (string $class): ClassNameNodePair => new ClassNameNodePair($class, $returnTypeNode), $returnTypeReferencedClasses), |
| 572 | + array_map(static function (string $class) use ($returnTypeNode, $returnOriginalCasePairs): ClassNameNodePair { |
| 573 | + $lowerClass = strtolower($class); |
| 574 | + if (isset($returnOriginalCasePairs[$lowerClass])) { |
| 575 | + return $returnOriginalCasePairs[$lowerClass]; |
| 576 | + } |
| 577 | + return new ClassNameNodePair($class, $returnTypeNode); |
| 578 | + }, $returnTypeReferencedClasses), |
549 | 579 | ClassNameUsageLocation::from(ClassNameUsageLocation::RETURN_TYPE, $locationData), |
550 | 580 | $this->checkClassCaseSensitivity, |
551 | 581 | ), |
@@ -807,4 +837,55 @@ private function checkImplicitlyNullableType( |
807 | 837 | ->build(); |
808 | 838 | } |
809 | 839 |
|
| 840 | + /** |
| 841 | + * @return array<string, ClassNameNodePair> |
| 842 | + */ |
| 843 | + private function getOriginalClassNamePairsFromTypeNode(Identifier|Name|ComplexType|null $typeNode): array |
| 844 | + { |
| 845 | + if ($typeNode === null) { |
| 846 | + return []; |
| 847 | + } |
| 848 | + |
| 849 | + if ($typeNode instanceof Name) { |
| 850 | + $originalName = $typeNode->getAttribute('originalName'); |
| 851 | + if (!$originalName instanceof Name) { |
| 852 | + return []; |
| 853 | + } |
| 854 | + |
| 855 | + $resolvedName = $typeNode->toString(); |
| 856 | + $originalParts = $originalName->getParts(); |
| 857 | + $resolvedParts = $typeNode->getParts(); |
| 858 | + |
| 859 | + $originalPartsCount = count($originalParts); |
| 860 | + $resolvedPartsCount = count($resolvedParts); |
| 861 | + |
| 862 | + if ($originalPartsCount <= $resolvedPartsCount) { |
| 863 | + $prefixParts = array_slice($resolvedParts, 0, $resolvedPartsCount - $originalPartsCount); |
| 864 | + $originalCaseClassName = implode('\\', array_merge($prefixParts, $originalParts)); |
| 865 | + } else { |
| 866 | + $originalCaseClassName = $originalName->toString(); |
| 867 | + } |
| 868 | + |
| 869 | + if ($originalCaseClassName === $resolvedName) { |
| 870 | + return []; |
| 871 | + } |
| 872 | + |
| 873 | + return [strtolower($resolvedName) => new ClassNameNodePair($originalCaseClassName, $typeNode)]; |
| 874 | + } |
| 875 | + |
| 876 | + if ($typeNode instanceof NullableType) { |
| 877 | + return $this->getOriginalClassNamePairsFromTypeNode($typeNode->type); |
| 878 | + } |
| 879 | + |
| 880 | + if ($typeNode instanceof UnionType || $typeNode instanceof IntersectionType) { |
| 881 | + $pairs = []; |
| 882 | + foreach ($typeNode->types as $innerType) { |
| 883 | + $pairs += $this->getOriginalClassNamePairsFromTypeNode($innerType); |
| 884 | + } |
| 885 | + return $pairs; |
| 886 | + } |
| 887 | + |
| 888 | + return []; |
| 889 | + } |
| 890 | + |
810 | 891 | } |
0 commit comments