diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 86f616953b9..bb5ec6c7808 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3660,7 +3660,8 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto return $result; } elseif ($expr instanceof BooleanOr || $expr instanceof BinaryOp\LogicalOr) { $leftResult = $this->processExprNode($stmt, $expr->left, $scope, $storage, $nodeCallback, $context->enterDeep()); - $rightResult = $this->processExprNode($stmt, $expr->right, $leftResult->getFalseyScope(), $storage, $nodeCallback, $context); + $leftFalseyScope = $leftResult->getFalseyScope(); + $rightResult = $this->processExprNode($stmt, $expr->right, $leftFalseyScope, $storage, $nodeCallback, $context); $rightExprType = $rightResult->getScope()->getType($expr->right); if ($rightExprType instanceof NeverType && $rightExprType->isExplicit()) { $leftMergedWithRightScope = $leftResult->getTruthyScope(); @@ -3668,7 +3669,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $leftMergedWithRightScope = $leftResult->getScope()->mergeWith($rightResult->getScope()); } - $this->callNodeCallbackWithExpression($nodeCallback, new BooleanOrNode($expr, $leftResult->getFalseyScope()), $scope, $storage, $context); + $this->callNodeCallbackWithExpression($nodeCallback, new BooleanOrNode($expr, $leftFalseyScope), $scope, $storage, $context); return new ExpressionResult( $leftMergedWithRightScope, @@ -3677,7 +3678,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto array_merge($leftResult->getThrowPoints(), $rightResult->getThrowPoints()), array_merge($leftResult->getImpurePoints(), $rightResult->getImpurePoints()), static fn (): MutatingScope => $leftMergedWithRightScope->filterByTruthyValue($expr), - static fn (): MutatingScope => $rightResult->getScope()->filterByFalseyValue($expr), + static fn (): MutatingScope => $rightResult->getScope()->filterByFalseyValue($expr->right), ); } elseif ($expr instanceof Coalesce) { $nonNullabilityResult = $this->ensureNonNullability($scope, $expr->left); diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 4e7036c6862..f9dfbbc5203 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1632,6 +1632,12 @@ public function testBug13980(): void $this->assertNoErrors($errors); } + public function testBug14207(): void + { + $errors = $this->runAnalyse(__DIR__ . '/data/bug-14207.php'); + $this->assertNoErrors($errors); + } + public function testBug13945(): void { $errors = $this->runAnalyse(__DIR__ . '/data/bug-13945.php'); diff --git a/tests/PHPStan/Analyser/data/bug-14207.php b/tests/PHPStan/Analyser/data/bug-14207.php new file mode 100644 index 00000000000..a378443b790 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-14207.php @@ -0,0 +1,153 @@ +namespace + ? strtoupper( $tag_name->node_name ) + : "{$tag_name->namespace} {$tag_name->node_name}"; + } + + assertType('non-falsy-string|uppercase-string', $tag_name); + + $x = ( + 'ADDRESS' === $tag_name || + 'APPLET' === $tag_name || + 'AREA' === $tag_name || + 'ARTICLE' === $tag_name || + 'ASIDE' === $tag_name || + 'BASE' === $tag_name || + 'BASEFONT' === $tag_name || + 'BGSOUND' === $tag_name || + 'BLOCKQUOTE' === $tag_name || + 'BODY' === $tag_name || + 'BR' === $tag_name || + 'BUTTON' === $tag_name || + 'CAPTION' === $tag_name || + 'CENTER' === $tag_name || + 'COL' === $tag_name || + 'COLGROUP' === $tag_name || + 'DD' === $tag_name || + 'DETAILS' === $tag_name || + 'DIR' === $tag_name || + 'DIV' === $tag_name || + 'DL' === $tag_name || + 'DT' === $tag_name || + 'EMBED' === $tag_name || + 'FIELDSET' === $tag_name || + 'FIGCAPTION' === $tag_name || + 'FIGURE' === $tag_name || + 'FOOTER' === $tag_name || + 'FORM' === $tag_name || + 'FRAME' === $tag_name || + 'FRAMESET' === $tag_name || + 'H1' === $tag_name || + 'H2' === $tag_name || + 'H3' === $tag_name || + 'H4' === $tag_name || + 'H5' === $tag_name || + 'H6' === $tag_name || + 'HEAD' === $tag_name || + 'HEADER' === $tag_name || + 'HGROUP' === $tag_name || + 'HR' === $tag_name || + 'HTML' === $tag_name || + 'IFRAME' === $tag_name || + 'IMG' === $tag_name || + 'INPUT' === $tag_name || + 'KEYGEN' === $tag_name || + 'LI' === $tag_name || + 'LINK' === $tag_name || + 'LISTING' === $tag_name || + 'MAIN' === $tag_name || + 'MARQUEE' === $tag_name || + 'MENU' === $tag_name || + 'META' === $tag_name || + 'NAV' === $tag_name || + 'NOEMBED' === $tag_name || + 'NOFRAMES' === $tag_name || + 'NOSCRIPT' === $tag_name || + 'OBJECT' === $tag_name || + 'OL' === $tag_name || + 'P' === $tag_name || + 'PARAM' === $tag_name || + 'PLAINTEXT' === $tag_name || + 'PRE' === $tag_name || + 'SCRIPT' === $tag_name || + 'SEARCH' === $tag_name || + 'SECTION' === $tag_name || + 'SELECT' === $tag_name || + 'SOURCE' === $tag_name || + 'STYLE' === $tag_name || + 'SUMMARY' === $tag_name || + 'TABLE' === $tag_name || + 'TBODY' === $tag_name || + 'TD' === $tag_name || + 'TEMPLATE' === $tag_name || + 'TEXTAREA' === $tag_name || + 'TFOOT' === $tag_name || + 'TH' === $tag_name || + 'THEAD' === $tag_name || + 'TITLE' === $tag_name || + 'TR' === $tag_name || + 'TRACK' === $tag_name || + 'UL' === $tag_name || + 'WBR' === $tag_name || + 'XMP' === $tag_name || + + // MathML. + 'math MI' === $tag_name || + 'math MO' === $tag_name || + 'math MN' === $tag_name || + 'math MS' === $tag_name || + 'math MTEXT' === $tag_name || + 'math ANNOTATION-XML' === $tag_name || + + // SVG. + 'svg DESC' === $tag_name || + 'svg FOREIGNOBJECT' === $tag_name || + 'svg TITLE' === $tag_name || + + // some random stuff + 'a1' === $tag_name || + 'a2' === $tag_name || + 'a3' === $tag_name || + 'a4' === $tag_name || + 'a5' === $tag_name || + 'a6' === $tag_name || + 'a7' === $tag_name || + 'a8' === $tag_name || + 'a9' === $tag_name + ); + + assertType('bool', $x); + if ($x) { + assertType("'a1'|'a2'|'a3'|'a4'|'a5'|'a6'|'a7'|'a8'|'a9'|'ADDRESS'|'APPLET'|'AREA'|'ARTICLE'|'ASIDE'|'BASE'|'BASEFONT'|'BGSOUND'|'BLOCKQUOTE'|'BODY'|'BR'|'BUTTON'|'CAPTION'|'CENTER'|'COL'|'COLGROUP'|'DD'|'DETAILS'|'DIR'|'DIV'|'DL'|'DT'|'EMBED'|'FIELDSET'|'FIGCAPTION'|'FIGURE'|'FOOTER'|'FORM'|'FRAME'|'FRAMESET'|'H1'|'H2'|'H3'|'H4'|'H5'|'H6'|'HEAD'|'HEADER'|'HGROUP'|'HR'|'HTML'|'IFRAME'|'IMG'|'INPUT'|'KEYGEN'|'LI'|'LINK'|'LISTING'|'MAIN'|'MARQUEE'|'math ANNOTATION-XML'|'math MI'|'math MN'|'math MO'|'math MS'|'math MTEXT'|'MENU'|'META'|'NAV'|'NOEMBED'|'NOFRAMES'|'NOSCRIPT'|'OBJECT'|'OL'|'P'|'PARAM'|'PLAINTEXT'|'PRE'|'SCRIPT'|'SEARCH'|'SECTION'|'SELECT'|'SOURCE'|'STYLE'|'SUMMARY'|'svg DESC'|'svg FOREIGNOBJECT'|'svg TITLE'|'TABLE'|'TBODY'|'TD'|'TEMPLATE'|'TEXTAREA'|'TFOOT'|'TH'|'THEAD'|'TITLE'|'TR'|'TRACK'|'UL'|'WBR'|'XMP'", $tag_name); + } + + return $x; + } +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-9400.php b/tests/PHPStan/Analyser/nsrt/bug-9400.php new file mode 100644 index 00000000000..ef588cdd0bf --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-9400.php @@ -0,0 +1,14 @@ +', $foo); +} diff --git a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php index 8f2e2ea4d1b..37563611b7e 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php @@ -223,4 +223,10 @@ public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLast $this->analyse([__DIR__ . '/data/boolean-not-report-always-true-last-condition.php'], $expectedErrors); } + public function testBug5984(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-5984.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-5984.php b/tests/PHPStan/Rules/Comparison/data/bug-5984.php new file mode 100644 index 00000000000..edf10403c15 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-5984.php @@ -0,0 +1,35 @@ +isDone() || $scanner->scanChar("\n")) { + return null; + } + + $min = $scanner->getColumn(); + + while (!$scanner->isDone() && $scanner->readChar() !== "\n") { + } + + return $min; + } +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-7156.php b/tests/PHPStan/Rules/Functions/data/bug-7156.php index 4c3f0f6666d..209a9decf54 100644 --- a/tests/PHPStan/Rules/Functions/data/bug-7156.php +++ b/tests/PHPStan/Rules/Functions/data/bug-7156.php @@ -32,7 +32,7 @@ function foobar2(mixed $data): void throw new \RuntimeException(); } - assertType("non-empty-array&hasOffsetValue('value', string)", $data); + assertType("non-empty-array&hasOffsetValue('value', string)", $data); foo($data); }