Skip to content

Commit c8c00f5

Browse files
authored
Implement BitwiseNotHandler (#4592)
1 parent 20e46e9 commit c8c00f5

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator\ExprHandler;
4+
5+
use Generator;
6+
use PhpParser\Node\Expr;
7+
use PhpParser\Node\Stmt;
8+
use PHPStan\Analyser\ExpressionContext;
9+
use PHPStan\Analyser\Generator\ExprAnalysisRequest;
10+
use PHPStan\Analyser\Generator\ExprAnalysisResult;
11+
use PHPStan\Analyser\Generator\ExprHandler;
12+
use PHPStan\Analyser\Generator\GeneratorScope;
13+
use PHPStan\Analyser\SpecifiedTypes;
14+
use PHPStan\DependencyInjection\AutowiredService;
15+
use PHPStan\Reflection\InitializerExprTypeResolver;
16+
17+
/**
18+
* @implements ExprHandler<Expr\BitwiseNot>
19+
*/
20+
#[AutowiredService]
21+
final class BitwiseNotHandler implements ExprHandler
22+
{
23+
24+
public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver)
25+
{
26+
}
27+
28+
public function supports(Expr $expr): bool
29+
{
30+
return $expr instanceof Expr\BitwiseNot;
31+
}
32+
33+
public function analyseExpr(Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback): Generator
34+
{
35+
$result = yield new ExprAnalysisRequest($stmt, $expr->expr, $scope, $context->enterDeep(), $alternativeNodeCallback);
36+
37+
return new ExprAnalysisResult(
38+
$this->initializerExprTypeResolver->getBitwiseNotTypeFromType($result->type),
39+
$this->initializerExprTypeResolver->getBitwiseNotTypeFromType($result->nativeType),
40+
$result->scope,
41+
hasYield: $result->hasYield,
42+
isAlwaysTerminating: $result->isAlwaysTerminating,
43+
throwPoints: $result->throwPoints,
44+
impurePoints: $result->impurePoints,
45+
specifiedTruthyTypes: new SpecifiedTypes(),
46+
specifiedFalseyTypes: new SpecifiedTypes(),
47+
specifiedNullTypes: new SpecifiedTypes(),
48+
);
49+
}
50+
51+
}

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2537,6 +2537,12 @@ public function getUnaryMinusType(Expr $expr, callable $getTypeCallback): Type
25372537
public function getBitwiseNotType(Expr $expr, callable $getTypeCallback): Type
25382538
{
25392539
$exprType = $getTypeCallback($expr);
2540+
2541+
return $this->getBitwiseNotTypeFromType($exprType);
2542+
}
2543+
2544+
public function getBitwiseNotTypeFromType(Type $exprType): Type
2545+
{
25402546
return TypeTraverser::map($exprType, static function (Type $type, callable $traverse): Type {
25412547
if ($type instanceof UnionType || $type instanceof IntersectionType) {
25422548
return $traverse($type);

tests/PHPStan/Analyser/Generator/data/gnsr.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ public function doMinus($a, $b, int $c, int $d): void
8787
assertNativeType('int', $c - $d);
8888
}
8989

90+
/**
91+
* @param int $a
92+
* @return void
93+
*/
94+
public function doBitwiseNot($a, int $b): void
95+
{
96+
assertType('int', ~$a);
97+
assertNativeType('int', ~$b);
98+
assertType('int', ~1);
99+
assertNativeType('int', ~1);
100+
assertType('int', ~$b);
101+
assertNativeType('int', ~$b);
102+
}
103+
90104
/**
91105
* @param int $a
92106
* @param int $b

0 commit comments

Comments
 (0)