|
29 | 29 | use PhpParser\Node\Stmt\ClassMethod; |
30 | 30 | use PhpParser\Node\Stmt\Function_; |
31 | 31 | use PhpParser\NodeFinder; |
| 32 | +use PHPStan\Analyser\Traverser\CloneTypeTraverser; |
| 33 | +use PHPStan\Analyser\Traverser\ConstructorClassTemplateTraverser; |
| 34 | +use PHPStan\Analyser\Traverser\GenericTypeTemplateTraverser; |
| 35 | +use PHPStan\Analyser\Traverser\InstanceOfClassTypeTraverser; |
| 36 | +use PHPStan\Analyser\Traverser\TransformStaticTypeTraverser; |
| 37 | +use PHPStan\Analyser\Traverser\VoidToNullTraverser; |
32 | 38 | use PHPStan\Node\ExecutionEndNode; |
33 | 39 | use PHPStan\Node\Expr\AlwaysRememberedExpr; |
34 | 40 | use PHPStan\Node\Expr\ExistingArrayDimFetch; |
|
107 | 113 | use PHPStan\Type\ExpressionTypeResolverExtensionRegistry; |
108 | 114 | use PHPStan\Type\FloatType; |
109 | 115 | use PHPStan\Type\GeneralizePrecision; |
110 | | -use PHPStan\Type\Generic\GenericClassStringType; |
111 | 116 | use PHPStan\Type\Generic\GenericObjectType; |
112 | 117 | use PHPStan\Type\Generic\GenericStaticType; |
113 | 118 | use PHPStan\Type\Generic\TemplateType; |
@@ -1137,23 +1142,9 @@ private function resolveType(string $exprString, Expr $node): Type |
1137 | 1142 | } |
1138 | 1143 | } else { |
1139 | 1144 | $classType = $this->getType($node->class); |
1140 | | - $classType = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use (&$uncertainty): Type { |
1141 | | - if ($type instanceof UnionType || $type instanceof IntersectionType) { |
1142 | | - return $traverse($type); |
1143 | | - } |
1144 | | - if ($type->getObjectClassNames() !== []) { |
1145 | | - $uncertainty = true; |
1146 | | - return $type; |
1147 | | - } |
1148 | | - if ($type instanceof GenericClassStringType) { |
1149 | | - $uncertainty = true; |
1150 | | - return $type->getGenericType(); |
1151 | | - } |
1152 | | - if ($type instanceof ConstantStringType) { |
1153 | | - return new ObjectType($type->getValue()); |
1154 | | - } |
1155 | | - return new MixedType(); |
1156 | | - }); |
| 1145 | + $traverser = new InstanceOfClassTypeTraverser(); |
| 1146 | + $classType = TypeTraverser::map($classType, $traverser); |
| 1147 | + $uncertainty = $traverser->getUncertainty(); |
1157 | 1148 | } |
1158 | 1149 |
|
1159 | 1150 | if ($classType->isSuperTypeOf(new MixedType())->yes()) { |
@@ -1287,17 +1278,7 @@ private function resolveType(string $exprString, Expr $node): Type |
1287 | 1278 |
|
1288 | 1279 | if ($node instanceof Expr\Clone_) { |
1289 | 1280 | $cloneType = TypeCombinator::intersect($this->getType($node->expr), new ObjectWithoutClassType()); |
1290 | | - |
1291 | | - return TypeTraverser::map($cloneType, static function (Type $type, callable $traverse): Type { |
1292 | | - if ($type instanceof UnionType || $type instanceof IntersectionType) { |
1293 | | - return $traverse($type); |
1294 | | - } |
1295 | | - if ($type instanceof ThisType) { |
1296 | | - return new StaticType($type->getClassReflection(), $type->getSubtractedType()); |
1297 | | - } |
1298 | | - |
1299 | | - return $type; |
1300 | | - }); |
| 1281 | + return TypeTraverser::map($cloneType, new CloneTypeTraverser()); |
1301 | 1282 | } |
1302 | 1283 |
|
1303 | 1284 | if ($node instanceof Node\Scalar\Int_) { |
@@ -2569,17 +2550,7 @@ private function transformVoidToNull(Type $type, Node $node): Type |
2569 | 2550 | return $type; |
2570 | 2551 | } |
2571 | 2552 |
|
2572 | | - return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { |
2573 | | - if ($type instanceof UnionType || $type instanceof IntersectionType) { |
2574 | | - return $traverse($type); |
2575 | | - } |
2576 | | - |
2577 | | - if ($type->isVoid()->yes()) { |
2578 | | - return new NullType(); |
2579 | | - } |
2580 | | - |
2581 | | - return $type; |
2582 | | - }); |
| 2553 | + return TypeTraverser::map($type, new VoidToNullTraverser()); |
2583 | 2554 | } |
2584 | 2555 |
|
2585 | 2556 | /** |
@@ -3244,21 +3215,7 @@ public function enterPropertyHook( |
3244 | 3215 |
|
3245 | 3216 | private function transformStaticType(Type $type): Type |
3246 | 3217 | { |
3247 | | - return TypeTraverser::map($type, function (Type $type, callable $traverse): Type { |
3248 | | - if (!$this->isInClass()) { |
3249 | | - return $type; |
3250 | | - } |
3251 | | - if ($type instanceof StaticType) { |
3252 | | - $classReflection = $this->getClassReflection(); |
3253 | | - $changedType = $type->changeBaseClass($classReflection); |
3254 | | - if ($classReflection->isFinal() && !$type instanceof ThisType) { |
3255 | | - $changedType = $changedType->getStaticObjectType(); |
3256 | | - } |
3257 | | - return $traverse($changedType); |
3258 | | - } |
3259 | | - |
3260 | | - return $traverse($type); |
3261 | | - }); |
| 3218 | + return TypeTraverser::map($type, new TransformStaticTypeTraverser($this)); |
3262 | 3219 | } |
3263 | 3220 |
|
3264 | 3221 | /** |
@@ -5985,19 +5942,12 @@ private function exactInstantiation(New_ $node, Name $className): Type |
5985 | 5942 | $constructorVariant = $constructorVariants[0]; |
5986 | 5943 | $classTemplateTypes = $classReflection->getTemplateTypeMap()->getTypes(); |
5987 | 5944 | $originalClassTemplateTypes = $classTemplateTypes; |
5988 | | - foreach ($constructorVariant->getParameters() as $parameter) { |
5989 | | - TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$classTemplateTypes): Type { |
5990 | | - if ($type instanceof TemplateType && array_key_exists($type->getName(), $classTemplateTypes)) { |
5991 | | - $classTemplateType = $classTemplateTypes[$type->getName()]; |
5992 | | - if ($classTemplateType instanceof TemplateType && $classTemplateType->getScope()->equals($type->getScope())) { |
5993 | | - unset($classTemplateTypes[$type->getName()]); |
5994 | | - } |
5995 | | - return $type; |
5996 | | - } |
5997 | 5945 |
|
5998 | | - return $traverse($type); |
5999 | | - }); |
| 5946 | + $traverser = new ConstructorClassTemplateTraverser($classTemplateTypes); |
| 5947 | + foreach ($constructorVariant->getParameters() as $parameter) { |
| 5948 | + TypeTraverser::map($parameter->getType(), $traverser); |
6000 | 5949 | } |
| 5950 | + $classTemplateTypes = $traverser->getClassTemplateTypes(); |
6001 | 5951 |
|
6002 | 5952 | if (count($classTemplateTypes) === count($originalClassTemplateTypes)) { |
6003 | 5953 | $propertyType = TypeCombinator::removeNull($this->getType($assignedToProperty)); |
@@ -6166,18 +6116,7 @@ classReflection: $classReflection->withTypes($types)->asFinal(), |
6166 | 6116 | [], |
6167 | 6117 | ); |
6168 | 6118 | } |
6169 | | - return TypeTraverser::map($newGenericType, static function (Type $type, callable $traverse) use ($resolvedTemplateTypeMap): Type { |
6170 | | - if ($type instanceof TemplateType && !$type->isArgument()) { |
6171 | | - $newType = $resolvedTemplateTypeMap->getType($type->getName()); |
6172 | | - if ($newType === null || $newType instanceof ErrorType) { |
6173 | | - return $type->getDefault() ?? $type->getBound(); |
6174 | | - } |
6175 | | - |
6176 | | - return TemplateTypeHelper::generalizeInferredTemplateType($type, $newType); |
6177 | | - } |
6178 | | - |
6179 | | - return $traverse($type); |
6180 | | - }); |
| 6119 | + return TypeTraverser::map($newGenericType, new GenericTypeTemplateTraverser($resolvedTemplateTypeMap)); |
6181 | 6120 | } |
6182 | 6121 |
|
6183 | 6122 | private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): ?Type |
|
0 commit comments