Skip to content

Commit 47c1045

Browse files
committed
Fix expr type in isset
1 parent ab367a6 commit 47c1045

12 files changed

Lines changed: 95 additions & 51 deletions

src/Analyser/Fiber/FiberScope.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,6 @@ public function getType(Expr $node): Type
6565
return $scope->getType($node);
6666
}
6767

68-
public function getScopeType(Expr $expr): Type
69-
{
70-
return $this->toMutatingScope()->getType($expr);
71-
}
72-
73-
public function getScopeNativeType(Expr $expr): Type
74-
{
75-
return $this->toMutatingScope()->getNativeType($expr);
76-
}
77-
7868
/** @api */
7969
public function getNativeType(Expr $expr): Type
8070
{

src/Analyser/MutatingScope.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -877,16 +877,6 @@ public function getType(Expr $node): Type
877877
return $this->resolvedTypes[$key];
878878
}
879879

880-
public function getScopeType(Expr $expr): Type
881-
{
882-
return $this->getType($expr);
883-
}
884-
885-
public function getScopeNativeType(Expr $expr): Type
886-
{
887-
return $this->getNativeType($expr);
888-
}
889-
890880
private function getNodeKey(Expr $node): string
891881
{
892882
$key = $this->exprPrinter->printExpr($node);

src/Analyser/NodeScopeResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6799,7 +6799,7 @@ private function processStmtVarAnnotation(MutatingScope $scope, ExpressionResult
67996799
$originalType = $scope->getType($defaultExpr);
68006800
$varTag = $variableLessTags[0];
68016801
if (!$originalType->equals($varTag->getType())) {
6802-
$this->callNodeCallback($nodeCallback, new VarTagChangedExpressionTypeNode($varTag, $defaultExpr), $scope, $storage);
6802+
$this->callNodeCallback($nodeCallback, new VarTagChangedExpressionTypeNode($varTag, clone $defaultExpr), $scope, $storage);
68036803
}
68046804
$scope = $scope->assignExpression($defaultExpr, $varTag->getType(), new MixedType());
68056805
}

src/Analyser/Scope.php

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,23 +108,6 @@ public function getNativeType(Expr $expr): Type;
108108

109109
public function getKeepVoidType(Expr $node): Type;
110110

111-
/**
112-
* The `getType()` method along with FNSR enabled
113-
* waits for the Expr analysis to be completed
114-
* in order to evaluate the type at the right place in the code.
115-
*
116-
* This prevents tricky bugs when reasoning about code like
117-
* `doFoo($a = 1, $a)`.
118-
*
119-
* Sometimes this is counter-productive because we actually want
120-
* to use the current Scope object contents to resolve the Expr type.
121-
*
122-
* In these cases use `getScopeType()`.
123-
*/
124-
public function getScopeType(Expr $expr): Type;
125-
126-
public function getScopeNativeType(Expr $expr): Type;
127-
128111
public function resolveName(Name $name): string;
129112

130113
public function resolveTypeByName(Name $name): TypeWithClassName;

src/Rules/IssetCheck.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str
5454
return null;
5555
}
5656

57-
$type = $this->treatPhpDocTypesAsCertain ? $scope->getScopeType($expr) : $scope->getScopeNativeType($expr);
57+
$type = $this->treatPhpDocTypesAsCertain ? $scope->getType($expr) : $scope->getNativeType($expr);
5858
if (!$type instanceof NeverType) {
5959
return $this->generateError(
6060
$type,
@@ -74,15 +74,15 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str
7474
return $error;
7575
} elseif ($expr instanceof Node\Expr\ArrayDimFetch && $expr->dim !== null) {
7676
$type = $this->treatPhpDocTypesAsCertain
77-
? $scope->getScopeType($expr->var)
78-
: $scope->getScopeNativeType($expr->var);
77+
? $scope->getType($expr->var)
78+
: $scope->getNativeType($expr->var);
7979
if (!$type->isOffsetAccessible()->yes()) {
8080
return $error ?? $this->checkUndefined($expr->var, $scope, $operatorDescription, $identifier);
8181
}
8282

8383
$dimType = $this->treatPhpDocTypesAsCertain
84-
? $scope->getScopeType($expr->dim)
85-
: $scope->getScopeNativeType($expr->dim);
84+
? $scope->getType($expr->dim)
85+
: $scope->getNativeType($expr->dim);
8686
$hasOffsetValue = $type->hasOffsetValueType($dimType);
8787
if ($hasOffsetValue->no()) {
8888
if (!$this->checkAdvancedIsset) {
@@ -241,7 +241,7 @@ static function (Type $type) use ($typeMessageCallback): ?string {
241241
}
242242

243243
$error = $this->generateError(
244-
$this->treatPhpDocTypesAsCertain ? $scope->getScopeType($expr) : $scope->getScopeNativeType($expr),
244+
$this->treatPhpDocTypesAsCertain ? $scope->getType($expr) : $scope->getNativeType($expr),
245245
sprintf('Expression %s', $operatorDescription),
246246
$typeMessageCallback,
247247
$identifier,
@@ -283,8 +283,8 @@ private function checkUndefined(Expr $expr, Scope $scope, string $operatorDescri
283283
}
284284

285285
if ($expr instanceof Node\Expr\ArrayDimFetch && $expr->dim !== null) {
286-
$type = $this->treatPhpDocTypesAsCertain ? $scope->getScopeType($expr->var) : $scope->getScopeNativeType($expr->var);
287-
$dimType = $this->treatPhpDocTypesAsCertain ? $scope->getScopeType($expr->dim) : $scope->getScopeNativeType($expr->dim);
286+
$type = $this->treatPhpDocTypesAsCertain ? $scope->getType($expr->var) : $scope->getNativeType($expr->var);
287+
$dimType = $this->treatPhpDocTypesAsCertain ? $scope->getType($expr->dim) : $scope->getNativeType($expr->dim);
288288
$hasOffsetValue = $type->hasOffsetValueType($dimType);
289289
if (!$type->isOffsetAccessible()->yes()) {
290290
return $this->checkUndefined($expr->var, $scope, $operatorDescription, $identifier);

src/Rules/Methods/NullsafeMethodCallRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function getNodeType(): string
2424

2525
public function processNode(Node $node, Scope $scope): array
2626
{
27-
$calledOnType = $scope->getScopeType($node->var);
27+
$calledOnType = $scope->getType($node->var);
2828
if (!$calledOnType->isNull()->no()) {
2929
return [];
3030
}

src/Rules/PhpDoc/VarTagTypeRuleHelper.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Analyser\Scope;
99
use PHPStan\DependencyInjection\AutowiredParameter;
1010
use PHPStan\DependencyInjection\AutowiredService;
11+
use PHPStan\Node\DeepNodeCloner;
1112
use PHPStan\Node\Expr\GetOffsetValueTypeExpr;
1213
use PHPStan\PhpDoc\NameScopeAlreadyBeingCreatedException;
1314
use PHPStan\PhpDoc\Tag\VarTag;
@@ -36,6 +37,7 @@ public function __construct(
3637
private TypeNodeResolver $typeNodeResolver,
3738
private FileTypeMapper $fileTypeMapper,
3839
private ReflectionProvider $reflectionProvider,
40+
private DeepNodeCloner $deepNodeCloner,
3941
#[AutowiredParameter(ref: '%reportWrongPhpDocTypeInVarTag%')]
4042
private bool $checkTypeAgainstPhpDocType,
4143
#[AutowiredParameter(ref: '%reportAnyTypeWideningInVarTag%')]
@@ -90,7 +92,7 @@ public function checkVarType(Scope $scope, Node\Expr $var, Node\Expr $expr, arra
9092
public function checkExprType(Scope $scope, Node\Expr $expr, Type $varTagType): array
9193
{
9294
$errors = [];
93-
$exprNativeType = $scope->getScopeNativeType($expr);
95+
$exprNativeType = $scope->getNativeType($this->deepNodeCloner->cloneNode($expr));
9496
$containsPhpStanType = $this->containsPhpStanType($varTagType);
9597
if ($this->shouldVarTagTypeBeReported($scope, $expr, $exprNativeType, $varTagType)) {
9698
$verbosity = VerbosityLevel::getRecommendedLevelByType($exprNativeType, $varTagType);
@@ -100,7 +102,7 @@ public function checkExprType(Scope $scope, Node\Expr $expr, Type $varTagType):
100102
$exprNativeType->describe($verbosity),
101103
))->identifier('varTag.nativeType')->build();
102104
} else {
103-
$exprType = $scope->getScopeType($expr);
105+
$exprType = $scope->getType($this->deepNodeCloner->cloneNode($expr));
104106
if (
105107
$this->shouldVarTagTypeBeReported($scope, $expr, $exprType, $varTagType)
106108
&& ($this->checkTypeAgainstPhpDocType || $containsPhpStanType)
@@ -115,7 +117,7 @@ public function checkExprType(Scope $scope, Node\Expr $expr, Type $varTagType):
115117
}
116118

117119
if (count($errors) === 0 && $containsPhpStanType) {
118-
$exprType = $scope->getScopeType($expr);
120+
$exprType = $scope->getType($this->deepNodeCloner->cloneNode($expr));
119121
if (!$exprType->equals($varTagType)) {
120122
$verbosity = VerbosityLevel::getRecommendedLevelByType($exprType, $varTagType);
121123
$errors[] = RuleErrorBuilder::message(sprintf(

src/Rules/Properties/NullsafePropertyFetchRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function getNodeType(): string
2828

2929
public function processNode(Node $node, Scope $scope): array
3030
{
31-
$calledOnType = $scope->getScopeType($node->var);
31+
$calledOnType = $scope->getType($node->var);
3232
if (!$calledOnType->isNull()->no()) {
3333
return [];
3434
}

tests/PHPStan/Rules/PhpDoc/VarTagChangedExpressionTypeRuleTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\PhpDoc;
44

5+
use PHPStan\Node\DeepNodeCloner;
56
use PHPStan\PhpDoc\TypeNodeResolver;
67
use PHPStan\Rules\Rule;
78
use PHPStan\Testing\RuleTestCase;
@@ -20,6 +21,7 @@ protected function getRule(): Rule
2021
$container->getByType(TypeNodeResolver::class),
2122
$container->getByType(FileTypeMapper::class),
2223
self::createReflectionProvider(),
24+
$container->getByType(DeepNodeCloner::class),
2325
true,
2426
true,
2527
));

tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\PhpDoc;
44

5+
use PHPStan\Node\DeepNodeCloner;
56
use PHPStan\PhpDoc\TypeNodeResolver;
67
use PHPStan\Rules\Rule;
78
use PHPStan\Testing\RuleTestCase;
@@ -28,6 +29,7 @@ protected function getRule(): Rule
2829
$container->getByType(TypeNodeResolver::class),
2930
$container->getByType(FileTypeMapper::class),
3031
self::createReflectionProvider(),
32+
$container->getByType(DeepNodeCloner::class),
3133
$this->checkTypeAgainstPhpDocType,
3234
$this->strictWideningCheck,
3335
),

0 commit comments

Comments
 (0)