|
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; |
@@ -1139,23 +1144,9 @@ private function resolveType(string $exprString, Expr $node): Type |
1139 | 1144 | } |
1140 | 1145 | } else { |
1141 | 1146 | $classType = $this->getType($node->class); |
1142 | | - $classType = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use (&$uncertainty): Type { |
1143 | | - if ($type instanceof UnionType || $type instanceof IntersectionType) { |
1144 | | - return $traverse($type); |
1145 | | - } |
1146 | | - if ($type->getObjectClassNames() !== []) { |
1147 | | - $uncertainty = true; |
1148 | | - return $type; |
1149 | | - } |
1150 | | - if ($type instanceof GenericClassStringType) { |
1151 | | - $uncertainty = true; |
1152 | | - return $type->getGenericType(); |
1153 | | - } |
1154 | | - if ($type instanceof ConstantStringType) { |
1155 | | - return new ObjectType($type->getValue()); |
1156 | | - } |
1157 | | - return new MixedType(); |
1158 | | - }); |
| 1147 | + $traverser = new InstanceOfClassTypeTraverser(); |
| 1148 | + $classType = TypeTraverser::map($classType, $traverser); |
| 1149 | + $uncertainty = $traverser->getUncertainty(); |
1159 | 1150 | } |
1160 | 1151 |
|
1161 | 1152 | if ($classType->isSuperTypeOf(new MixedType())->yes()) { |
@@ -1289,17 +1280,7 @@ private function resolveType(string $exprString, Expr $node): Type |
1289 | 1280 |
|
1290 | 1281 | if ($node instanceof Expr\Clone_) { |
1291 | 1282 | $cloneType = TypeCombinator::intersect($this->getType($node->expr), new ObjectWithoutClassType()); |
1292 | | - |
1293 | | - return TypeTraverser::map($cloneType, static function (Type $type, callable $traverse): Type { |
1294 | | - if ($type instanceof UnionType || $type instanceof IntersectionType) { |
1295 | | - return $traverse($type); |
1296 | | - } |
1297 | | - if ($type instanceof ThisType) { |
1298 | | - return new StaticType($type->getClassReflection(), $type->getSubtractedType()); |
1299 | | - } |
1300 | | - |
1301 | | - return $type; |
1302 | | - }); |
| 1283 | + return TypeTraverser::map($cloneType, new CloneTypeTraverser()); |
1303 | 1284 | } |
1304 | 1285 |
|
1305 | 1286 | if ($node instanceof Node\Scalar\Int_) { |
@@ -2571,17 +2552,7 @@ private function transformVoidToNull(Type $type, Node $node): Type |
2571 | 2552 | return $type; |
2572 | 2553 | } |
2573 | 2554 |
|
2574 | | - return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { |
2575 | | - if ($type instanceof UnionType || $type instanceof IntersectionType) { |
2576 | | - return $traverse($type); |
2577 | | - } |
2578 | | - |
2579 | | - if ($type->isVoid()->yes()) { |
2580 | | - return new NullType(); |
2581 | | - } |
2582 | | - |
2583 | | - return $type; |
2584 | | - }); |
| 2555 | + return TypeTraverser::map($type, new VoidToNullTraverser()); |
2585 | 2556 | } |
2586 | 2557 |
|
2587 | 2558 | /** |
@@ -3246,21 +3217,7 @@ public function enterPropertyHook( |
3246 | 3217 |
|
3247 | 3218 | private function transformStaticType(Type $type): Type |
3248 | 3219 | { |
3249 | | - return TypeTraverser::map($type, function (Type $type, callable $traverse): Type { |
3250 | | - if (!$this->isInClass()) { |
3251 | | - return $type; |
3252 | | - } |
3253 | | - if ($type instanceof StaticType) { |
3254 | | - $classReflection = $this->getClassReflection(); |
3255 | | - $changedType = $type->changeBaseClass($classReflection); |
3256 | | - if ($classReflection->isFinal() && !$type instanceof ThisType) { |
3257 | | - $changedType = $changedType->getStaticObjectType(); |
3258 | | - } |
3259 | | - return $traverse($changedType); |
3260 | | - } |
3261 | | - |
3262 | | - return $traverse($type); |
3263 | | - }); |
| 3220 | + return TypeTraverser::map($type, new TransformStaticTypeTraverser($this)); |
3264 | 3221 | } |
3265 | 3222 |
|
3266 | 3223 | /** |
@@ -5987,19 +5944,12 @@ private function exactInstantiation(New_ $node, Name $className): Type |
5987 | 5944 | $constructorVariant = $constructorVariants[0]; |
5988 | 5945 | $classTemplateTypes = $classReflection->getTemplateTypeMap()->getTypes(); |
5989 | 5946 | $originalClassTemplateTypes = $classTemplateTypes; |
5990 | | - foreach ($constructorVariant->getParameters() as $parameter) { |
5991 | | - TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$classTemplateTypes): Type { |
5992 | | - if ($type instanceof TemplateType && array_key_exists($type->getName(), $classTemplateTypes)) { |
5993 | | - $classTemplateType = $classTemplateTypes[$type->getName()]; |
5994 | | - if ($classTemplateType instanceof TemplateType && $classTemplateType->getScope()->equals($type->getScope())) { |
5995 | | - unset($classTemplateTypes[$type->getName()]); |
5996 | | - } |
5997 | | - return $type; |
5998 | | - } |
5999 | 5947 |
|
6000 | | - return $traverse($type); |
6001 | | - }); |
| 5948 | + $traverser = new ConstructorClassTemplateTraverser($classTemplateTypes); |
| 5949 | + foreach ($constructorVariant->getParameters() as $parameter) { |
| 5950 | + TypeTraverser::map($parameter->getType(), $traverser); |
6002 | 5951 | } |
| 5952 | + $classTemplateTypes = $traverser->getClassTemplateTypes(); |
6003 | 5953 |
|
6004 | 5954 | if (count($classTemplateTypes) === count($originalClassTemplateTypes)) { |
6005 | 5955 | $propertyType = TypeCombinator::removeNull($this->getType($assignedToProperty)); |
@@ -6168,18 +6118,7 @@ classReflection: $classReflection->withTypes($types)->asFinal(), |
6168 | 6118 | [], |
6169 | 6119 | ); |
6170 | 6120 | } |
6171 | | - return TypeTraverser::map($newGenericType, static function (Type $type, callable $traverse) use ($resolvedTemplateTypeMap): Type { |
6172 | | - if ($type instanceof TemplateType && !$type->isArgument()) { |
6173 | | - $newType = $resolvedTemplateTypeMap->getType($type->getName()); |
6174 | | - if ($newType === null || $newType instanceof ErrorType) { |
6175 | | - return $type->getDefault() ?? $type->getBound(); |
6176 | | - } |
6177 | | - |
6178 | | - return TemplateTypeHelper::generalizeInferredTemplateType($type, $newType); |
6179 | | - } |
6180 | | - |
6181 | | - return $traverse($type); |
6182 | | - }); |
| 6121 | + return TypeTraverser::map($newGenericType, new GenericTypeTemplateTraverser($resolvedTemplateTypeMap)); |
6183 | 6122 | } |
6184 | 6123 |
|
6185 | 6124 | private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): ?Type |
|
0 commit comments