From 5e75140ca575406d01df12d856c98ec12b565cc3 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Sun, 17 Jan 2021 14:28:28 -0500 Subject: [PATCH] Fix #5020 - remove previous catch var assertions when assigning inside catch --- src/Psalm/Context.php | 4 +++ .../Analyzer/Statements/Block/TryAnalyzer.php | 8 +++++ tests/Template/FunctionTemplateAssertTest.php | 35 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/Psalm/Context.php b/src/Psalm/Context.php index f62616160..6a8af0cd0 100644 --- a/src/Psalm/Context.php +++ b/src/Psalm/Context.php @@ -630,6 +630,10 @@ class Context } } + /** + * This method is used after assignments to variables to remove any existing + * items in $vars_in_scope that are now made redundant by an update to some data + */ public function removeDescendents( string $remove_var_id, ?Union $existing_type = null, diff --git a/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php index 58399df1a..b5c1424b5 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Block/TryAnalyzer.php @@ -306,6 +306,14 @@ class TryAnalyzer ) ); + // removes dependent vars from $context + $catch_context->removeDescendents( + $catch_var_id, + null, + $catch_context->vars_in_scope[$catch_var_id], + $statements_analyzer + ); + $catch_context->vars_possibly_in_scope[$catch_var_id] = true; $location = new CodeLocation($statements_analyzer->getSource(), $catch->var); diff --git a/tests/Template/FunctionTemplateAssertTest.php b/tests/Template/FunctionTemplateAssertTest.php index 00613e89b..eab898d6b 100644 --- a/tests/Template/FunctionTemplateAssertTest.php +++ b/tests/Template/FunctionTemplateAssertTest.php @@ -732,6 +732,41 @@ class FunctionTemplateAssertTest extends TestCase } }' ], + 'assertSameOnMemoizedMethodCall' => [ + 'getMessage()); + } + + try { + validateUsername("invalid#1"); + } catch (Exception $e) { + assertSame("b", $e->getMessage()); + } + } + + /** + * @psalm-template ExpectedType + * @psalm-param ExpectedType $expected + * @psalm-param mixed $actual + * @psalm-assert =ExpectedType $actual + */ + function assertSame($expected, $actual): void { + if ($actual !== $expected) { + throw new Exception("Bad"); + } + } + + function validateUsername(string $username): void { + if (strlen($username) < 5) { + throw new Exception("Username must be at least 5 characters long"); + } + }' + ], ]; }