From 8fa35c22283794f03abedc92048affa25dfe5dd4 Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sun, 27 Nov 2022 11:45:40 -0400 Subject: [PATCH] Variables should outlive namespaces (#8779) Variables in PHP are not namespaced. In other words, namespaces share the context with the file they are located in. See https://3v4l.org/2qvrC Fixes vimeo/psalm#8778 --- .../Internal/Analyzer/NamespaceAnalyzer.php | 17 +++++++++-------- tests/Config/ConfigTest.php | 13 ++++++++----- tests/NamespaceTest.php | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php b/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php index a3d658b6e01..de86b5b650d 100644 --- a/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php @@ -87,16 +87,17 @@ public function collectAnalyzableInformation(): void if ($leftover_stmts) { $statements_analyzer = new StatementsAnalyzer($this, new NodeDataProvider()); - $context = new Context(); - $context->is_global = true; - $context->defineGlobals(); - $context->collect_exceptions = $codebase->config->check_for_throws_in_global_scope; - $statements_analyzer->analyze($leftover_stmts, $context, null, true); - $file_context = $this->source->context; - if ($file_context) { - $file_context->mergeExceptions($context); + + if ($file_context !== null) { + $context = $file_context; + } else { + $context = new Context(); + $context->is_global = true; + $context->defineGlobals(); + $context->collect_exceptions = $codebase->config->check_for_throws_in_global_scope; } + $statements_analyzer->analyze($leftover_stmts, $context, null, true); } } diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 442cdbfa600..3fff4089e50 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -152,7 +152,7 @@ public function testIgnoreMissingProjectDirectory(): void $config = $this->project_analyzer->getConfig(); $this->assertTrue($config->isInProjectDirs(realpath('src/Psalm/Type.php'))); - $this->assertFalse($config->isInProjectDirs(realpath(__DIR__.'/../../').'/does/not/exist/FileAnalyzer.php')); + $this->assertFalse($config->isInProjectDirs(realpath(__DIR__ . '/../../') . '/does/not/exist/FileAnalyzer.php')); $this->assertFalse($config->isInProjectDirs(realpath('examples/TemplateScanner.php'))); } @@ -1159,15 +1159,18 @@ function example1(): void { ord($_GET["str"]); } - $glob1 = 0; - error_reporting($glob1); + $z = $glob1; + $z = 0; + error_reporting($z); + $old = $_GET["str"]; $_GET["str"] = 0; error_reporting($_GET["str"]); + $_GET["str"] = $old; function example2(): void { - global $glob1, $glob2, $glob3; - error_reporting($glob1); + global $z, $glob2, $glob3; + error_reporting($z); ord($glob2["str"]); $glob3->func(); ord($_GET["str"]); diff --git a/tests/NamespaceTest.php b/tests/NamespaceTest.php index e6b53727a77..3f31eddb055 100644 --- a/tests/NamespaceTest.php +++ b/tests/NamespaceTest.php @@ -71,6 +71,24 @@ function foo() : void { $c = $argv; }', ], + 'varsAreNotScoped' => [ + 'code' => ' [ + '$a===' => "'1'", + '$bc===' => "'2'", + ], + ], ]; }