Skip to content

Commit e2388a7

Browse files
authored
forbidXxxOnMixed: more generic detection of unknown caller (#149)
1 parent 4481bba commit e2388a7

File tree

4 files changed

+45
-10
lines changed

4 files changed

+45
-10
lines changed

src/Rule/ForbidFetchOnMixedRule.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use PhpParser\PrettyPrinter\Standard;
1212
use PHPStan\Analyser\Scope;
1313
use PHPStan\Rules\Rule;
14-
use PHPStan\Type\MixedType;
14+
use PHPStan\Type\TypeUtils;
1515
use function get_class;
1616
use function sprintf;
1717

@@ -66,9 +66,9 @@ private function processFetch(Node $node, Scope $scope): array
6666
return [];
6767
}
6868

69-
$callerType = $scope->getType($caller);
69+
$callerType = TypeUtils::toBenevolentUnion($scope->getType($caller));
7070

71-
if ($callerType instanceof MixedType) {
71+
if ($callerType->getObjectTypeOrClassStringObjectType()->getObjectClassNames() === []) {
7272
$name = $node->name;
7373
$property = $name instanceof Identifier
7474
? $this->printer->prettyPrint([$name])

src/Rule/ForbidMethodCallOnMixedRule.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use PhpParser\PrettyPrinter\Standard;
1313
use PHPStan\Analyser\Scope;
1414
use PHPStan\Rules\Rule;
15-
use PHPStan\Type\MixedType;
15+
use PHPStan\Type\TypeUtils;
1616
use function get_class;
1717
use function sprintf;
1818

@@ -67,9 +67,9 @@ private function checkCall(CallLike $node, Scope $scope): array
6767
return [];
6868
}
6969

70-
$callerType = $scope->getType($caller);
70+
$callerType = TypeUtils::toBenevolentUnion($scope->getType($caller));
7171

72-
if ($callerType instanceof MixedType) {
72+
if ($callerType->getObjectTypeOrClassStringObjectType()->getObjectClassNames() === []) {
7373
$name = $node->name;
7474
$method = $name instanceof Identifier ? $this->printer->prettyPrint([$name]) : $this->printer->prettyPrintExpr($name);
7575

tests/Rule/data/ForbidFetchOnMixedRuleTest/code.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,30 @@ class Foo {
99
public static ?int $staticProperty = null;
1010
}
1111

12-
$fn = function (mixed $mixed, $unknown, array $array, ReflectionClass $reflection) {
12+
$fn = function (mixed $mixed, $unknown, string $string, array $array, ReflectionClass $reflection, ?Foo $fooOrNull) {
1313
(new Foo)->property;
1414
Foo::$staticProperty;
1515

16+
/** @var class-string $classString */
17+
$classString = '';
18+
$classString::$staticProperty; // error: Property fetch ::$staticProperty is prohibited on unknown type ($classString)
19+
20+
/** @var class-string<Foo> $classString2 */
21+
$classString2 = '';
22+
$classString2::$staticProperty;
23+
24+
$string::$staticProperty; // error: Property fetch ::$staticProperty is prohibited on unknown type ($string)
25+
1626
$mixed->fetch1; // error: Property fetch ->fetch1 is prohibited on unknown type ($mixed)
1727
$mixed::$fetch1; // error: Property fetch ::$fetch1 is prohibited on unknown type ($mixed)
1828
$unknown->fetch2; // error: Property fetch ->fetch2 is prohibited on unknown type ($unknown)
1929
$unknown::$fetch2; // error: Property fetch ::$fetch2 is prohibited on unknown type ($unknown)
2030
$array[0]->fetch3; // error: Property fetch ->fetch3 is prohibited on unknown type ($array[0])
21-
$reflection->newInstance()->fetch4;
31+
32+
$fooOrNull->property;
33+
$fooOrNull?->property;
34+
35+
$reflection->newInstance()->property; // error: Property fetch ->property is prohibited on unknown type ($reflection->newInstance())
36+
/** @var ReflectionClass<Foo> $reflection */
37+
$reflection->newInstance()->property;
2238
};

tests/Rule/data/ForbidMethodCallOnMixedRule/code.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,39 @@ public function method() {}
99
public static function staticMethod() {}
1010
}
1111

12-
$fn = function (mixed $mixed, $unknown, array $array, ReflectionClass $reflection) {
12+
$fn = function (mixed $mixed, $unknown, array $array, string $string, ?Foo $fooOrNull, ReflectionClass $reflection) {
1313

1414
$foo = new Foo();
1515
$foo->method();
1616
$foo?->method();
1717
Foo::staticMethod();
1818
$foo::staticMethod();
1919

20+
$fooOrNull->method();
21+
$fooOrNull?->method();
22+
$fooOrNull->staticMethod();
23+
$fooOrNull?->staticMethod();
24+
25+
/** @var class-string $classString */
26+
$classString = '';
27+
$classString::staticMethod(); // error: Method call ::staticMethod() is prohibited on unknown type ($classString)
28+
29+
/** @var class-string<Foo> $classString2 */
30+
$classString2 = '';
31+
$classString2::staticMethod();
32+
33+
$string::staticMethod(); // error: Method call ::staticMethod() is prohibited on unknown type ($string)
34+
2035
$mixed->call1(); // error: Method call ->call1() is prohibited on unknown type ($mixed)
2136
$mixed?->call1(); // error: Method call ->call1() is prohibited on unknown type ($mixed)
2237
$mixed::call1(); // error: Method call ::call1() is prohibited on unknown type ($mixed)
2338
$unknown->call2(); // error: Method call ->call2() is prohibited on unknown type ($unknown)
2439
$unknown?->call2(); // error: Method call ->call2() is prohibited on unknown type ($unknown)
2540
$unknown::call2(); // error: Method call ::call2() is prohibited on unknown type ($unknown)
2641
$array[0]->call3(); // error: Method call ->call3() is prohibited on unknown type ($array[0])
27-
$reflection->newInstance()->call4();
42+
43+
44+
$reflection->newInstance()->method(); // error: Method call ->method() is prohibited on unknown type ($reflection->newInstance())
45+
/** @var ReflectionClass<Foo> $reflection */
46+
$reflection->newInstance()->method();
2847
};

0 commit comments

Comments
 (0)