Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<Node\Expr\ClassConstFetch>
Expand Down Expand Up @@ -72,7 +71,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$referencedClasses = TypeCombinator::removeNull($classTypeResult->getType())->getObjectTypeOrClassStringObjectType()->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::getFromClassExpression($classTypeResult->getType());
}

$errors = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<MethodCallableNode>
Expand Down Expand Up @@ -54,7 +52,7 @@ public function processNode(Node $node, Scope $scope): array

$methodName = $node->getName()->name;
$methodCalledOnType = $scope->getType($node->getVar());
$referencedClasses = TypeCombinator::intersect($methodCalledOnType, new ObjectWithoutClassType())->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::get($methodCalledOnType);

$errors = [];

Expand Down
4 changes: 1 addition & 3 deletions src/Rules/RestrictedUsage/RestrictedMethodUsageRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<MethodCall>
Expand Down Expand Up @@ -54,7 +52,7 @@ public function processNode(Node $node, Scope $scope): array

$methodName = $node->name->name;
$methodCalledOnType = $scope->getType($node->var);
$referencedClasses = TypeCombinator::intersect($methodCalledOnType, new ObjectWithoutClassType())->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::get($methodCalledOnType);

$errors = [];

Expand Down
4 changes: 1 addition & 3 deletions src/Rules/RestrictedUsage/RestrictedPropertyUsageRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<Node\Expr\PropertyFetch>
Expand Down Expand Up @@ -53,7 +51,7 @@ public function processNode(Node $node, Scope $scope): array

$propertyName = $node->name->name;
$propertyCalledOnType = $scope->getType($node->var);
$referencedClasses = TypeCombinator::intersect($propertyCalledOnType, new ObjectWithoutClassType())->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::get($propertyCalledOnType);

$errors = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<StaticMethodCallableNode>
Expand Down Expand Up @@ -73,7 +72,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$referencedClasses = TypeCombinator::removeNull($classTypeResult->getType())->getObjectTypeOrClassStringObjectType()->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::getFromClassExpression($classTypeResult->getType());
}

$errors = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<Node\Expr\StaticCall>
Expand Down Expand Up @@ -72,7 +71,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$referencedClasses = TypeCombinator::removeNull($classTypeResult->getType())->getObjectTypeOrClassStringObjectType()->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::getFromClassExpression($classTypeResult->getType());
}

$errors = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<Node\Expr\StaticPropertyFetch>
Expand Down Expand Up @@ -65,14 +64,14 @@
$scope,
$node->class,
'', // We don't care about the error message
static fn (Type $type): bool => $type->canAccessProperties()->yes() && $type->hasInstanceProperty($propertyName)->yes(),
static fn (Type $type): bool => $type->canAccessProperties()->yes() && $type->hasStaticProperty($propertyName)->yes(),

Check warning on line 67 in src/Rules/RestrictedUsage/RestrictedStaticPropertyUsageRule.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ $scope, $node->class, '', // We don't care about the error message - static fn (Type $type): bool => $type->canAccessProperties()->yes() && $type->hasStaticProperty($propertyName)->yes(), + static fn (Type $type): bool => $type->canAccessProperties()->yes() && !$type->hasStaticProperty($propertyName)->no(), ); if ($classTypeResult->getType() instanceof ErrorType) {

Check warning on line 67 in src/Rules/RestrictedUsage/RestrictedStaticPropertyUsageRule.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ $scope, $node->class, '', // We don't care about the error message - static fn (Type $type): bool => $type->canAccessProperties()->yes() && $type->hasStaticProperty($propertyName)->yes(), + static fn (Type $type): bool => !$type->canAccessProperties()->no() && $type->hasStaticProperty($propertyName)->yes(), ); if ($classTypeResult->getType() instanceof ErrorType) {
);

if ($classTypeResult->getType() instanceof ErrorType) {
return [];
}

$referencedClasses = TypeCombinator::removeNull($classTypeResult->getType())->getObjectTypeOrClassStringObjectType()->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::getFromClassExpression($classTypeResult->getType());
}

$errors = [];
Expand Down
59 changes: 59 additions & 0 deletions src/Rules/RestrictedUsage/RestrictedUsageObjectClassNames.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\RestrictedUsage;

use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use function array_values;

final class RestrictedUsageObjectClassNames
{

/**
* Class names of the members of the type, so that the object part of a union
* is still checked when it is combined with null, false, string, ...
* Members without a class name contribute nothing.
*
* Iterates the members directly instead of intersecting with `object`,
* as this runs for every method call and property fetch.
*
* @return list<string>
*/
public static function get(Type $type): array
{
return self::collect($type, false);
}

/**
* Same as get(), for the class expression of a static access (`$expr::foo()`),
* where a member can also be a class-string.
*
* @return list<string>
*/
public static function getFromClassExpression(Type $type): array
{
return self::collect($type, true);
}

/**
* @return list<string>
*/
private static function collect(Type $type, bool $acceptClassStrings): array
{
$members = $type instanceof UnionType ? $type->getTypes() : [$type];

$classNames = [];
foreach ($members as $member) {
if ($acceptClassStrings) {
$member = $member->getObjectTypeOrClassStringObjectType();
}

foreach ($member->getObjectClassNames() as $className) {
$classNames[$className] = $className;
}
}

return array_values($classNames);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\TypeCombinator;

/**
* @implements Rule<Cast\String_>
Expand Down Expand Up @@ -45,7 +43,7 @@ public function processNode(Node $node, Scope $scope): array
}

$exprType = $scope->getType($node->expr);
$referencedClasses = TypeCombinator::intersect($exprType, new ObjectWithoutClassType())->getObjectClassNames();
$referencedClasses = RestrictedUsageObjectClassNames::get($exprType);

$errors = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ public function testBug15681(): void
'Cannot access FOO',
123,
],
[
'Cannot access FOO',
172,
],
[
'Cannot access FOO',
177,
],
[
'Cannot access FOO',
182,
],
[
'Cannot access FOO',
193,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ public function testBug15681(): void
'Cannot call doFoo',
65,
],
[
'Cannot call doFoo',
141,
],
[
'Cannot call doFoo',
142,
],
[
'Cannot call doFoo',
143,
],
[
'Cannot call doFoo',
158,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ public function testBug15681(): void
'Cannot call doFoo',
57,
],
[
'Cannot call doFoo',
133,
],
[
'Cannot call doFoo',
134,
],
[
'Cannot call doFoo',
135,
],
[
'Cannot call doFoo',
156,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ public function testBug15681(): void
'Cannot access $foo',
62,
],
[
'Cannot access $foo',
137,
],
[
'Cannot access $foo',
138,
],
[
'Cannot access $foo',
139,
],
[
'Cannot access $foo',
157,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ public function testBug15681(): void
'Cannot call doFoo',
121,
],
[
'Cannot call doFoo',
170,
],
[
'Cannot call doFoo',
175,
],
[
'Cannot call doFoo',
180,
],
[
'Cannot call doFoo',
191,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@ public function testBug15681(): void
'Cannot call doFoo',
120,
],
[
'Cannot call doFoo',
169,
],
[
'Cannot call doFoo',
174,
],
[
'Cannot call doFoo',
179,
],
[
'Cannot call doFoo',
190,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ public function testBug15681(): void
'Cannot access $foo',
122,
],
[
'Cannot access $foo',
171,
],
[
'Cannot access $foo',
176,
],
[
'Cannot access $foo',
181,
],
[
'Cannot access $foo',
192,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ public function testBug15681(): void
'Cannot call __toString',
68,
],
[
'Cannot call __toString',
145,
],
[
'Cannot call __toString',
146,
],
[
'Cannot call __toString',
147,
],
[
'Cannot call __toString',
159,
],
]);
}

Expand Down
Loading
Loading