Skip to content

Commit 8968dad

Browse files
committed
Merge remote-tracking branch 'origin/1.12.x' into 2.0.x
2 parents 8f2307e + 9263039 commit 8968dad

File tree

55 files changed

+303
-87
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+303
-87
lines changed

conf/config.level4.neon

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ services:
6767
checkAlwaysTrueInstanceof: %checkAlwaysTrueInstanceof%
6868
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
6969
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
70+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
7071
tags:
7172
- phpstan.rules.rule
7273

@@ -76,6 +77,7 @@ services:
7677
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
7778
bleedingEdge: %featureToggles.bleedingEdge%
7879
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
80+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
7981
tags:
8082
- phpstan.rules.rule
8183

@@ -85,6 +87,7 @@ services:
8587
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
8688
bleedingEdge: %featureToggles.bleedingEdge%
8789
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
90+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
8891
tags:
8992
- phpstan.rules.rule
9093

@@ -93,6 +96,7 @@ services:
9396
arguments:
9497
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
9598
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
99+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
96100
tags:
97101
- phpstan.rules.rule
98102

@@ -142,6 +146,7 @@ services:
142146
class: PHPStan\Rules\Comparison\DoWhileLoopConstantConditionRule
143147
arguments:
144148
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
149+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
145150
tags:
146151
- phpstan.rules.rule
147152

@@ -150,13 +155,15 @@ services:
150155
arguments:
151156
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
152157
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
158+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
153159
tags:
154160
- phpstan.rules.rule
155161

156162
-
157163
class: PHPStan\Rules\Comparison\IfConstantConditionRule
158164
arguments:
159165
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
166+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
160167
tags:
161168
- phpstan.rules.rule
162169

@@ -166,6 +173,7 @@ services:
166173
checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall%
167174
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
168175
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
176+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
169177
tags:
170178
- phpstan.rules.rule
171179

@@ -175,6 +183,7 @@ services:
175183
checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall%
176184
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
177185
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
186+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
178187
tags:
179188
- phpstan.rules.rule
180189

@@ -184,6 +193,7 @@ services:
184193
checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall%
185194
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
186195
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
196+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
187197
tags:
188198
- phpstan.rules.rule
189199

@@ -192,6 +202,7 @@ services:
192202
arguments:
193203
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
194204
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
205+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
195206

196207
-
197208
class: PHPStan\Rules\DeadCode\BetterNoopRule
@@ -210,6 +221,7 @@ services:
210221
class: PHPStan\Rules\Comparison\NumberComparisonOperatorsConstantConditionRule
211222
arguments:
212223
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
224+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
213225
tags:
214226
- phpstan.rules.rule
215227

@@ -219,6 +231,7 @@ services:
219231
checkAlwaysTrueStrictComparison: %checkAlwaysTrueStrictComparison%
220232
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
221233
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
234+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
222235
tags:
223236
- phpstan.rules.rule
224237

@@ -228,11 +241,13 @@ services:
228241
checkAlwaysTrueLooseComparison: %checkAlwaysTrueLooseComparison%
229242
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
230243
reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition%
244+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
231245

232246
-
233247
class: PHPStan\Rules\Comparison\TernaryOperatorConstantConditionRule
234248
arguments:
235249
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
250+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
236251
tags:
237252
- phpstan.rules.rule
238253

@@ -241,6 +256,7 @@ services:
241256
arguments:
242257
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
243258
disable: %featureToggles.disableUnreachableBranchesRules%
259+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
244260
tags:
245261
- phpstan.rules.rule
246262

@@ -249,20 +265,23 @@ services:
249265
arguments:
250266
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
251267
disable: %featureToggles.disableUnreachableBranchesRules%
268+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
252269
tags:
253270
- phpstan.rules.rule
254271

255272
-
256273
class: PHPStan\Rules\Comparison\WhileLoopAlwaysFalseConditionRule
257274
arguments:
258275
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
276+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
259277
tags:
260278
- phpstan.rules.rule
261279

262280
-
263281
class: PHPStan\Rules\Comparison\WhileLoopAlwaysTrueConditionRule
264282
arguments:
265283
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
284+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
266285
tags:
267286
- phpstan.rules.rule
268287

conf/config.level5.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ services:
3434
class: PHPStan\Rules\Functions\ArrayFilterRule
3535
arguments:
3636
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
37+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
3738

3839
-
3940
class: PHPStan\Rules\Functions\ArrayValuesRule
4041
arguments:
4142
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
43+
treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain%
4244

4345
-
4446
class: PHPStan\Rules\Functions\CallUserFuncRule

conf/config.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ parameters:
156156
treatPhpDocTypesAsCertain: true
157157
usePathConstantsAsConstantString: false
158158
rememberPossiblyImpureFunctionValues: true
159+
tips:
160+
treatPhpDocTypesAsCertain: true
159161
tipsOfTheDay: true
160162
reportMagicMethods: false
161163
reportMagicProperties: false

conf/parametersSchema.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ parametersSchema:
122122
deprecationRulesInstalled: bool()
123123
inferPrivatePropertyTypeFromConstructor: bool()
124124

125+
tips: structure([
126+
treatPhpDocTypesAsCertain: bool()
127+
])
125128
tipsOfTheDay: bool()
126129
reportMaybes: bool()
127130
reportMaybesInMethodSignatures: bool()

src/Analyser/MutatingScope.php

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,7 @@ private function resolveType(string $exprString, Expr $node): Type
12011201
return new ObjectType(Closure::class);
12021202
}
12031203

1204-
$classType = $this->resolveTypeByName($node->class);
1204+
$classType = $this->resolveTypeByNameWithLateStaticBinding($node->class, $node->name);
12051205
$methodName = $node->name->toString();
12061206
if (!$classType->hasMethod($methodName)->yes()) {
12071207
return new ObjectType(Closure::class);
@@ -2081,19 +2081,7 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
20812081
if ($this->nativeTypesPromoted) {
20822082
$typeCallback = function () use ($node): Type {
20832083
if ($node->class instanceof Name) {
2084-
$staticMethodCalledOnType = $this->resolveTypeByName($node->class);
2085-
if (
2086-
$staticMethodCalledOnType instanceof StaticType
2087-
&& !in_array($node->class->toLowerString(), ['self', 'static', 'parent'], true)
2088-
) {
2089-
$methodReflectionCandidate = $this->getMethodReflection(
2090-
$staticMethodCalledOnType,
2091-
$node->name->name,
2092-
);
2093-
if ($methodReflectionCandidate !== null && $methodReflectionCandidate->isStatic()) {
2094-
$staticMethodCalledOnType = $staticMethodCalledOnType->getStaticObjectType();
2095-
}
2096-
}
2084+
$staticMethodCalledOnType = $this->resolveTypeByNameWithLateStaticBinding($node->class, $node->name);
20972085
} else {
20982086
$staticMethodCalledOnType = $this->getNativeType($node->class);
20992087
}
@@ -2118,19 +2106,7 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
21182106

21192107
$typeCallback = function () use ($node): Type {
21202108
if ($node->class instanceof Name) {
2121-
$staticMethodCalledOnType = $this->resolveTypeByName($node->class);
2122-
if (
2123-
$staticMethodCalledOnType instanceof StaticType
2124-
&& !in_array($node->class->toLowerString(), ['self', 'static', 'parent'], true)
2125-
) {
2126-
$methodReflectionCandidate = $this->getMethodReflection(
2127-
$staticMethodCalledOnType,
2128-
$node->name->name,
2129-
);
2130-
if ($methodReflectionCandidate !== null && $methodReflectionCandidate->isStatic()) {
2131-
$staticMethodCalledOnType = $staticMethodCalledOnType->getStaticObjectType();
2132-
}
2133-
}
2109+
$staticMethodCalledOnType = $this->resolveTypeByNameWithLateStaticBinding($node->class, $node->name);
21342110
} else {
21352111
$staticMethodCalledOnType = TypeCombinator::removeNull($this->getType($node->class))->getObjectTypeOrClassStringObjectType();
21362112
}
@@ -2779,6 +2755,26 @@ public function resolveTypeByName(Name $name): TypeWithClassName
27792755
return new ObjectType($originalClass);
27802756
}
27812757

2758+
private function resolveTypeByNameWithLateStaticBinding(Name $class, Node\Identifier $name): TypeWithClassName
2759+
{
2760+
$classType = $this->resolveTypeByName($class);
2761+
2762+
if (
2763+
$classType instanceof StaticType
2764+
&& !in_array($class->toLowerString(), ['self', 'static', 'parent'], true)
2765+
) {
2766+
$methodReflectionCandidate = $this->getMethodReflection(
2767+
$classType,
2768+
$name->name,
2769+
);
2770+
if ($methodReflectionCandidate !== null && $methodReflectionCandidate->isStatic()) {
2771+
$classType = $classType->getStaticObjectType();
2772+
}
2773+
}
2774+
2775+
return $classType;
2776+
}
2777+
27822778
/**
27832779
* @api
27842780
* @param mixed $value

src/Analyser/TypeSpecifier.php

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,39 +1082,6 @@ private function specifyTypesForConstantBinaryExpression(
10821082
)->setRootExpr($rootExpr));
10831083
}
10841084

1085-
if (
1086-
!$context->null()
1087-
&& $exprNode instanceof FuncCall
1088-
&& count($exprNode->getArgs()) === 1
1089-
&& $exprNode->name instanceof Name
1090-
&& in_array(strtolower((string) $exprNode->name), ['strlen', 'mb_strlen'], true)
1091-
&& $constantType instanceof ConstantIntegerType
1092-
) {
1093-
if ($constantType->getValue() < 0) {
1094-
return $this->create($exprNode->getArgs()[0]->value, new NeverType(), $context, $scope)->setRootExpr($rootExpr);
1095-
}
1096-
1097-
if ($context->truthy() || $constantType->getValue() === 0) {
1098-
$newContext = $context;
1099-
if ($constantType->getValue() === 0) {
1100-
$newContext = $newContext->negate();
1101-
}
1102-
$argType = $scope->getType($exprNode->getArgs()[0]->value);
1103-
if ($argType->isString()->yes()) {
1104-
$funcTypes = $this->create($exprNode, $constantType, $context, $scope)->setRootExpr($rootExpr);
1105-
1106-
$accessory = new AccessoryNonEmptyStringType();
1107-
if ($constantType->getValue() >= 2) {
1108-
$accessory = new AccessoryNonFalsyStringType();
1109-
}
1110-
$valueTypes = $this->create($exprNode->getArgs()[0]->value, $accessory, $newContext, $scope)->setRootExpr($rootExpr);
1111-
1112-
return $funcTypes->unionWith($valueTypes);
1113-
}
1114-
}
1115-
1116-
}
1117-
11181085
return null;
11191086
}
11201087

@@ -2079,6 +2046,42 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
20792046
}
20802047
}
20812048

2049+
if (
2050+
!$context->null()
2051+
&& $unwrappedLeftExpr instanceof FuncCall
2052+
&& count($unwrappedLeftExpr->getArgs()) === 1
2053+
&& $unwrappedLeftExpr->name instanceof Name
2054+
&& in_array(strtolower((string) $unwrappedLeftExpr->name), ['strlen', 'mb_strlen'], true)
2055+
&& $rightType->isInteger()->yes()
2056+
) {
2057+
if (IntegerRangeType::fromInterval(null, -1)->isSuperTypeOf($rightType)->yes()) {
2058+
return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, $scope)->setRootExpr($expr);
2059+
}
2060+
2061+
$isZero = (new ConstantIntegerType(0))->isSuperTypeOf($rightType);
2062+
if ($isZero->yes()) {
2063+
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2064+
return $funcTypes->unionWith(
2065+
$this->create($unwrappedLeftExpr->getArgs()[0]->value, new ConstantStringType(''), $context, $scope)->setRootExpr($expr),
2066+
);
2067+
}
2068+
2069+
if ($context->truthy() && IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($rightType)->yes()) {
2070+
$argType = $scope->getType($unwrappedLeftExpr->getArgs()[0]->value);
2071+
if ($argType->isString()->yes()) {
2072+
$funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr);
2073+
2074+
$accessory = new AccessoryNonEmptyStringType();
2075+
if (IntegerRangeType::fromInterval(2, null)->isSuperTypeOf($rightType)->yes()) {
2076+
$accessory = new AccessoryNonFalsyStringType();
2077+
}
2078+
$valueTypes = $this->create($unwrappedLeftExpr->getArgs()[0]->value, $accessory, $context, $scope)->setRootExpr($expr);
2079+
2080+
return $funcTypes->unionWith($valueTypes);
2081+
}
2082+
}
2083+
}
2084+
20822085
if (
20832086
$context->true()
20842087
&& $unwrappedLeftExpr instanceof FuncCall
@@ -2143,14 +2146,11 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
21432146
}
21442147
}
21452148

2146-
if ($rightType->isInteger()->yes() || $rightType->isString()->yes()) {
2149+
if ($rightType->isString()->yes()) {
21472150
$types = null;
2148-
foreach ($rightType->getFiniteTypes() as $finiteType) {
2149-
if ($finiteType->isString()->yes()) {
2150-
$specifiedType = $this->specifyTypesForConstantStringBinaryExpression($unwrappedLeftExpr, $finiteType, $context, $scope, $expr);
2151-
} else {
2152-
$specifiedType = $this->specifyTypesForConstantBinaryExpression($unwrappedLeftExpr, $finiteType, $context, $scope, $expr);
2153-
}
2151+
foreach ($rightType->getConstantStrings() as $constantString) {
2152+
$specifiedType = $this->specifyTypesForConstantStringBinaryExpression($unwrappedLeftExpr, $constantString, $context, $scope, $expr);
2153+
21542154
if ($specifiedType === null) {
21552155
continue;
21562156
}

src/Rules/Classes/ImpossibleInstanceOfRule.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function __construct(
2525
private bool $checkAlwaysTrueInstanceof,
2626
private bool $treatPhpDocTypesAsCertain,
2727
private bool $reportAlwaysTrueInLastCondition,
28+
private bool $treatPhpDocTypesAsCertainTip,
2829
)
2930
{
3031
}
@@ -71,6 +72,10 @@ public function processNode(Node $node, Scope $scope): array
7172
return $ruleErrorBuilder;
7273
}
7374

75+
if (!$this->treatPhpDocTypesAsCertainTip) {
76+
return $ruleErrorBuilder;
77+
}
78+
7479
return $ruleErrorBuilder->treatPhpDocTypesAsCertainTip();
7580
};
7681

0 commit comments

Comments
 (0)