Skip to content

Commit 868ed2e

Browse files
authored
Merge branch '2.1.x' into equals
2 parents 9312250 + ce257d9 commit 868ed2e

31 files changed

+797
-155
lines changed

conf/config.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ rules:
227227
- PHPStan\Rules\RestrictedUsage\RestrictedStaticMethodUsageRule
228228
- PHPStan\Rules\RestrictedUsage\RestrictedStaticMethodCallableUsageRule
229229
- PHPStan\Rules\RestrictedUsage\RestrictedStaticPropertyUsageRule
230+
- PHPStan\Rules\RestrictedUsage\RestrictedUsageOfDeprecatedStringCastRule
230231

231232
conditionalTags:
232233
PHPStan\Rules\Exceptions\MissingCheckedExceptionInFunctionThrowsRule:

src/Analyser/NodeScopeResolver.php

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@
206206
use function array_merge;
207207
use function array_pop;
208208
use function array_reverse;
209-
use function array_shift;
210209
use function array_slice;
211210
use function array_values;
212211
use function base64_decode;
@@ -1567,12 +1566,10 @@ private function processStmtNode(
15671566
$throwPoints = $condResult->getThrowPoints();
15681567
$impurePoints = $condResult->getImpurePoints();
15691568
$fullCondExpr = null;
1570-
$defaultCondExprs = [];
15711569
foreach ($stmt->cases as $caseNode) {
15721570
if ($caseNode->cond !== null) {
15731571
$condExpr = new BinaryOp\Equal($stmt->cond, $caseNode->cond);
15741572
$fullCondExpr = $fullCondExpr === null ? $condExpr : new BooleanOr($fullCondExpr, $condExpr);
1575-
$defaultCondExprs[] = new BinaryOp\NotEqual($stmt->cond, $caseNode->cond);
15761573
$caseResult = $this->processExprNode($stmt, $caseNode->cond, $scopeForBranches, $nodeCallback, ExpressionContext::createDeep());
15771574
$scopeForBranches = $caseResult->getScope();
15781575
$hasYield = $hasYield || $caseResult->hasYield();
@@ -1583,11 +1580,6 @@ private function processStmtNode(
15831580
$hasDefaultCase = true;
15841581
$fullCondExpr = null;
15851582
$branchScope = $scopeForBranches;
1586-
$defaultConditions = $this->createBooleanAndFromExpressions($defaultCondExprs);
1587-
if ($defaultConditions !== null) {
1588-
$branchScope = $this->processExprNode($stmt, $defaultConditions, $scope, static function (): void {
1589-
}, ExpressionContext::createDeep())->getTruthyScope()->filterByTruthyValue($defaultConditions);
1590-
}
15911583
}
15921584

15931585
$branchScope = $branchScope->mergeWith($prevScope);
@@ -6709,29 +6701,6 @@ private function getPhpDocReturnType(ResolvedPhpDocBlock $resolvedPhpDoc, Type $
67096701
return null;
67106702
}
67116703

6712-
/**
6713-
* @param list<Expr> $expressions
6714-
*/
6715-
private function createBooleanAndFromExpressions(array $expressions): ?Expr
6716-
{
6717-
if (count($expressions) === 0) {
6718-
return null;
6719-
}
6720-
6721-
if (count($expressions) === 1) {
6722-
return $expressions[0];
6723-
}
6724-
6725-
$left = array_shift($expressions);
6726-
$right = $this->createBooleanAndFromExpressions($expressions);
6727-
6728-
if ($right === null) {
6729-
throw new ShouldNotHappenException();
6730-
}
6731-
6732-
return new BooleanAnd($left, $right);
6733-
}
6734-
67356704
/**
67366705
* @param array<Node> $nodes
67376706
* @return list<Node\Stmt>

src/Analyser/TypeSpecifier.php

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,45 +1643,24 @@ private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\
16431643
$leftType = $scope->getType($binaryOperation->left);
16441644
$rightType = $scope->getType($binaryOperation->right);
16451645

1646-
$rightExpr = $this->extractExpression($binaryOperation->right);
1647-
$leftExpr = $this->extractExpression($binaryOperation->left);
1648-
1649-
if (
1650-
$leftType instanceof ConstantScalarType
1651-
&& !$rightExpr instanceof ConstFetch
1652-
&& !$rightExpr instanceof ClassConstFetch
1653-
) {
1654-
return [$binaryOperation->right, $leftType, $rightType];
1655-
} elseif (
1656-
$rightType instanceof ConstantScalarType
1657-
&& !$leftExpr instanceof ConstFetch
1658-
&& !$leftExpr instanceof ClassConstFetch
1659-
) {
1660-
return [$binaryOperation->left, $rightType, $leftType];
1646+
$rightExpr = $binaryOperation->right;
1647+
if ($rightExpr instanceof AlwaysRememberedExpr) {
1648+
$rightExpr = $rightExpr->getExpr();
16611649
}
16621650

1663-
return null;
1664-
}
1665-
1666-
/**
1667-
* @return array{Expr, Type, Type}|null
1668-
*/
1669-
private function findEnumTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\BinaryOp $binaryOperation): ?array
1670-
{
1671-
$leftType = $scope->getType($binaryOperation->left);
1672-
$rightType = $scope->getType($binaryOperation->right);
1673-
1674-
$rightExpr = $this->extractExpression($binaryOperation->right);
1675-
$leftExpr = $this->extractExpression($binaryOperation->left);
1651+
$leftExpr = $binaryOperation->left;
1652+
if ($leftExpr instanceof AlwaysRememberedExpr) {
1653+
$leftExpr = $leftExpr->getExpr();
1654+
}
16761655

16771656
if (
1678-
$leftType->getEnumCases() === [$leftType]
1657+
$leftType instanceof ConstantScalarType
16791658
&& !$rightExpr instanceof ConstFetch
16801659
&& !$rightExpr instanceof ClassConstFetch
16811660
) {
16821661
return [$binaryOperation->right, $leftType, $rightType];
16831662
} elseif (
1684-
$rightType->getEnumCases() === [$rightType]
1663+
$rightType instanceof ConstantScalarType
16851664
&& !$leftExpr instanceof ConstFetch
16861665
&& !$leftExpr instanceof ClassConstFetch
16871666
) {
@@ -1691,11 +1670,6 @@ private function findEnumTypeExpressionsFromBinaryOperation(Scope $scope, Node\E
16911670
return null;
16921671
}
16931672

1694-
private function extractExpression(Expr $expr): Expr
1695-
{
1696-
return $expr instanceof AlwaysRememberedExpr ? $expr->getExpr() : $expr;
1697-
}
1698-
16991673
/** @api */
17001674
public function create(
17011675
Expr $expr,
@@ -2087,27 +2061,6 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif
20872061
) {
20882062
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context)->setRootExpr($expr);
20892063
}
2090-
2091-
if (!$context->null() && TypeCombinator::containsNull($otherType)) {
2092-
if ($constantType->toBoolean()->isTrue()->yes()) {
2093-
$otherType = TypeCombinator::remove($otherType, new NullType());
2094-
}
2095-
2096-
if (!$otherType->isSuperTypeOf($constantType)->no()) {
2097-
return $this->create($exprNode, TypeCombinator::intersect($constantType, $otherType), $context, $scope)->setRootExpr($expr);
2098-
}
2099-
}
2100-
}
2101-
2102-
$expressions = $this->findEnumTypeExpressionsFromBinaryOperation($scope, $expr);
2103-
if ($expressions !== null) {
2104-
$exprNode = $expressions[0];
2105-
$enumCaseObjectType = $expressions[1];
2106-
$otherType = $expressions[2];
2107-
2108-
if (!$context->null()) {
2109-
return $this->create($exprNode, TypeCombinator::intersect($enumCaseObjectType, $otherType), $context, $scope)->setRootExpr($expr);
2110-
}
21112064
}
21122065

21132066
$leftType = $scope->getType($expr->left);

src/Rules/Classes/InstantiationRule.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PhpParser\Node\Expr\New_;
77
use PHPStan\Analyser\Scope;
8+
use PHPStan\DependencyInjection\Container;
89
use PHPStan\Internal\SprintfHelper;
910
use PHPStan\Reflection\ClassReflection;
1011
use PHPStan\Reflection\ParametersAcceptorSelector;
@@ -15,6 +16,8 @@
1516
use PHPStan\Rules\ClassNameUsageLocation;
1617
use PHPStan\Rules\FunctionCallParametersCheck;
1718
use PHPStan\Rules\IdentifierRuleError;
19+
use PHPStan\Rules\RestrictedUsage\RestrictedMethodUsageExtension;
20+
use PHPStan\Rules\RestrictedUsage\RewrittenDeclaringClassMethodReflection;
1821
use PHPStan\Rules\Rule;
1922
use PHPStan\Rules\RuleErrorBuilder;
2023
use PHPStan\ShouldNotHappenException;
@@ -33,6 +36,7 @@ final class InstantiationRule implements Rule
3336
{
3437

3538
public function __construct(
39+
private Container $container,
3640
private ReflectionProvider $reflectionProvider,
3741
private FunctionCallParametersCheck $check,
3842
private ClassNameCheck $classCheck,
@@ -197,6 +201,28 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $
197201
->build();
198202
}
199203

204+
/** @var RestrictedMethodUsageExtension[] $restrictedUsageExtensions */
205+
$restrictedUsageExtensions = $this->container->getServicesByTag(RestrictedMethodUsageExtension::METHOD_EXTENSION_TAG);
206+
207+
foreach ($restrictedUsageExtensions as $extension) {
208+
$restrictedUsage = $extension->isRestrictedMethodUsage($constructorReflection, $scope);
209+
if ($restrictedUsage === null) {
210+
continue;
211+
}
212+
213+
if ($classReflection->getName() !== $constructorReflection->getDeclaringClass()->getName()) {
214+
$rewrittenConstructorReflection = new RewrittenDeclaringClassMethodReflection($classReflection, $constructorReflection);
215+
$rewrittenRestrictedUsage = $extension->isRestrictedMethodUsage($rewrittenConstructorReflection, $scope);
216+
if ($rewrittenRestrictedUsage === null) {
217+
continue;
218+
}
219+
}
220+
221+
$messages[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
222+
->identifier($restrictedUsage->identifier)
223+
->build();
224+
}
225+
200226
$classDisplayName = SprintfHelper::escapeFormatString($classReflection->getDisplayName());
201227

202228
return array_merge($messages, $this->check->check(

src/Rules/RestrictedUsage/RestrictedClassConstantUsageRule.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ public function processNode(Node $node, Scope $scope): array
8686
continue;
8787
}
8888

89+
if ($classReflection->getName() !== $constantReflection->getDeclaringClass()->getName()) {
90+
$rewrittenConstantReflection = new RewrittenDeclaringClassClassConstantReflection($classReflection, $constantReflection);
91+
$rewrittenRestrictedUsage = $extension->isRestrictedClassConstantUsage($rewrittenConstantReflection, $scope);
92+
if ($rewrittenRestrictedUsage === null) {
93+
continue;
94+
}
95+
}
96+
8997
$errors[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
9098
->identifier($restrictedUsage->identifier)
9199
->build();

src/Rules/RestrictedUsage/RestrictedStaticMethodCallableUsageRule.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ public function processNode(Node $node, Scope $scope): array
8787
continue;
8888
}
8989

90+
if ($classReflection->getName() !== $methodReflection->getDeclaringClass()->getName()) {
91+
$rewrittenMethodReflection = new RewrittenDeclaringClassMethodReflection($classReflection, $methodReflection);
92+
$rewrittenRestrictedUsage = $extension->isRestrictedMethodUsage($rewrittenMethodReflection, $scope);
93+
if ($rewrittenRestrictedUsage === null) {
94+
continue;
95+
}
96+
}
97+
9098
$errors[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
9199
->identifier($restrictedUsage->identifier)
92100
->build();

src/Rules/RestrictedUsage/RestrictedStaticMethodUsageRule.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ public function processNode(Node $node, Scope $scope): array
8686
continue;
8787
}
8888

89+
if ($classReflection->getName() !== $methodReflection->getDeclaringClass()->getName()) {
90+
$rewrittenMethodReflection = new RewrittenDeclaringClassMethodReflection($classReflection, $methodReflection);
91+
$rewrittenRestrictedUsage = $extension->isRestrictedMethodUsage($rewrittenMethodReflection, $scope);
92+
if ($rewrittenRestrictedUsage === null) {
93+
continue;
94+
}
95+
}
96+
8997
$errors[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
9098
->identifier($restrictedUsage->identifier)
9199
->build();

src/Rules/RestrictedUsage/RestrictedStaticPropertyUsageRule.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ public function processNode(Node $node, Scope $scope): array
8686
continue;
8787
}
8888

89+
if ($classReflection->getName() !== $propertyReflection->getDeclaringClass()->getName()) {
90+
$rewrittenPropertyReflection = new RewrittenDeclaringClassPropertyReflection($classReflection, $propertyReflection);
91+
$rewrittenRestrictedUsage = $extension->isRestrictedPropertyUsage($rewrittenPropertyReflection, $scope);
92+
if ($rewrittenRestrictedUsage === null) {
93+
continue;
94+
}
95+
}
96+
8997
$errors[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
9098
->identifier($restrictedUsage->identifier)
9199
->build();
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\RestrictedUsage;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\Cast;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\DependencyInjection\Container;
9+
use PHPStan\Reflection\ReflectionProvider;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Rules\RuleErrorBuilder;
12+
13+
/**
14+
* @implements Rule<Cast\String_>
15+
*/
16+
final class RestrictedUsageOfDeprecatedStringCastRule implements Rule
17+
{
18+
19+
public function __construct(
20+
private Container $container,
21+
private ReflectionProvider $reflectionProvider,
22+
)
23+
{
24+
}
25+
26+
public function getNodeType(): string
27+
{
28+
return Cast\String_::class;
29+
}
30+
31+
public function processNode(Node $node, Scope $scope): array
32+
{
33+
/** @var RestrictedMethodUsageExtension[] $extensions */
34+
$extensions = $this->container->getServicesByTag(RestrictedMethodUsageExtension::METHOD_EXTENSION_TAG);
35+
if ($extensions === []) {
36+
return [];
37+
}
38+
39+
$exprType = $scope->getType($node->expr);
40+
$referencedClasses = $exprType->getObjectClassNames();
41+
42+
$errors = [];
43+
44+
foreach ($referencedClasses as $referencedClass) {
45+
if (!$this->reflectionProvider->hasClass($referencedClass)) {
46+
continue;
47+
}
48+
49+
$classReflection = $this->reflectionProvider->getClass($referencedClass);
50+
if (!$classReflection->hasNativeMethod('__toString')) {
51+
continue;
52+
}
53+
54+
$methodReflection = $classReflection->getNativeMethod('__toString');
55+
foreach ($extensions as $extension) {
56+
$restrictedUsage = $extension->isRestrictedMethodUsage($methodReflection, $scope);
57+
if ($restrictedUsage === null) {
58+
continue;
59+
}
60+
61+
$errors[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
62+
->identifier($restrictedUsage->identifier)
63+
->build();
64+
}
65+
}
66+
67+
return $errors;
68+
}
69+
70+
}

0 commit comments

Comments
 (0)