Skip to content
Permalink
Browse files

Fix #2177 - mark variables in try block as potentially undefined

  • Loading branch information
muglug committed Nov 9, 2019
1 parent 62a3598 commit 94d4b876ba15ea02b5f9fc92e2a188a6f1f6a7fe
@@ -1217,8 +1217,6 @@ public function getFunctionArgumentAtPosition(string $file_path, Position $posit
*/
public function getSignatureInformation(string $function_symbol) : ?\LanguageServerProtocol\SignatureInformation
{
$params = null;
if (strpos($function_symbol, '::') !== false) {
$declaring_method_id = $this->methods->getDeclaringMethodId($function_symbol);
@@ -78,6 +78,8 @@ public static function analyze(
$old_unreferenced_vars = $try_context->unreferenced_vars;
$newly_unreferenced_vars = [];
$old_context_vars = $context->vars_in_scope;
if ($statements_analyzer->analyze($stmt->stmts, $context) === false) {
return false;
}
@@ -159,10 +161,18 @@ public static function analyze(
'TypeDoesNotContainType',
];
$definitely_newly_assigned_var_ids = $newly_assigned_var_ids;
/** @var int $i */
foreach ($stmt->catches as $i => $catch) {
$catch_context = clone $original_context;
foreach ($catch_context->vars_in_scope as $var_id => $type) {
if (!isset($old_context_vars[$var_id])) {
$type->possibly_undefined_from_try = true;
}
}
$fq_catch_classes = [];
$catch_var_name = $catch->var->name;
@@ -312,6 +322,10 @@ function ($fq_catch_class) use ($codebase) {
}
}
$old_catch_assigned_var_ids = $catch_context->referenced_var_ids;
$catch_context->assigned_var_ids = [];
$statements_analyzer->analyze($catch->stmts, $catch_context);
// recalculate in case there's a no-return clause
@@ -327,6 +341,11 @@ function ($fq_catch_class) use ($codebase) {
}
}
/** @var array<string, bool> */
$new_catch_assigned_var_ids = $catch_context->assigned_var_ids;
$catch_context->assigned_var_ids += $old_catch_assigned_var_ids;
$context->referenced_var_ids = array_intersect_key(
$catch_context->referenced_var_ids,
$context->referenced_var_ids
@@ -369,7 +388,16 @@ function ($fq_catch_class) use ($codebase) {
}
if ($catch_actions[$i] !== [ScopeAnalyzer::ACTION_END]) {
$definitely_newly_assigned_var_ids = array_intersect_key(
$new_catch_assigned_var_ids,
$definitely_newly_assigned_var_ids
);
foreach ($catch_context->vars_in_scope as $var_id => $type) {
if (!isset($old_context_vars[$var_id])) {
$type->possibly_undefined_from_try = false;
}
if ($stmt_control_actions === [ScopeAnalyzer::ACTION_END]) {
$context->vars_in_scope[$var_id] = $type;
} elseif (isset($context->vars_in_scope[$var_id])
@@ -386,11 +414,19 @@ function ($fq_catch_class) use ($codebase) {
$catch_context->vars_possibly_in_scope,
$context->vars_possibly_in_scope
);
} elseif ($stmt->finally) {
$context->vars_possibly_in_scope = array_merge(
$catch_context->vars_possibly_in_scope,
$context->vars_possibly_in_scope
);
} else {
if ($stmt->finally) {
$context->vars_possibly_in_scope = array_merge(
$catch_context->vars_possibly_in_scope,
$context->vars_possibly_in_scope
);
}
}
}
foreach ($definitely_newly_assigned_var_ids as $var_id => $_) {
if (isset($context->vars_in_scope[$var_id])) {
$context->vars_in_scope[$var_id]->possibly_undefined_from_try = false;
}
}
@@ -272,6 +272,30 @@ public static function analyze(
} else {
$stmt->inferredType = clone $context->vars_in_scope[$var_name];
if ($stmt->inferredType->possibly_undefined_from_try && !$context->inside_isset) {
if ($context->is_global) {
if (IssueBuffer::accepts(
new PossiblyUndefinedGlobalVariable(
'Possibly undefined global variable ' . $var_name . ' defined in try block',
new CodeLocation($statements_analyzer->getSource(), $stmt)
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
} else {
if (IssueBuffer::accepts(
new PossiblyUndefinedVariable(
'Possibly undefined variable ' . $var_name . ' defined in try block',
new CodeLocation($statements_analyzer->getSource(), $stmt)
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
}
}
if ($codebase->store_node_types
&& !$context->collect_initializations
&& !$context->collect_mutations
@@ -60,8 +60,9 @@ protected function execute(InputInterface $i, OutputInterface $o)
$plugin_list = ($this->plugin_list_factory)($current_dir, $config_file_path);
$plugin_name = $i->getArgument('pluginName');
try {
$plugin_name = $i->getArgument('pluginName');
assert(is_string($plugin_name));
$plugin_class = $plugin_list->resolvePluginClass($plugin_name);
@@ -60,8 +60,9 @@ protected function execute(InputInterface $i, OutputInterface $o)
$plugin_list = ($this->plugin_list_factory)($current_dir, $config_file_path);
$plugin_name = $i->getArgument('pluginName');
try {
$plugin_name = $i->getArgument('pluginName');
assert(is_string($plugin_name));
$plugin_class = $plugin_list->resolvePluginClass($plugin_name);
@@ -110,14 +110,15 @@ function foo() : bool {
'MixedMethodCall' => \Psalm\Config::REPORT_INFO,
],
],
'issetAfterTryCatch' => [
'issetAfterTryCatchWithoutAssignmentInCatch' => [
'<?php
function test(): string {
throw new Exception("bad");
}
$a = "foo";
try {
$a = "foo";
$var = test();
} catch (Exception $e) {
echo "bad";
@@ -127,23 +128,45 @@ function test(): string {
echo $a;',
],
'issetAfterTryCatchWithCombinedType' => [
'issetAfterTryCatchWithAssignmentInCatch' => [
'<?php
function test(): string {
throw new Exception("bad");
}
$a = "foo";
try {
$a = "foo";
$var = test();
} catch (Exception $e) {
$var = "bad";
}
if (isset($var)) {}
echo $var;
echo $a;',
],
'issetAfterTryCatchWithIfInCatch' => [
'<?php
function test(): string {
throw new Exception("bad");
}
function foo() : void {
$a = null;
$params = null;
try {
$a = test();
$params = $a;
} catch (\Exception $exception) {
$params = "hello";
}
echo $params;
}',
],
'noRedundantConditionsInFinally' => [
'<?php
function doThings(): void {}
@@ -318,6 +341,32 @@ function foo() : bool {
}',
'error_message' => 'InvalidReturnType',
],
'preventPossiblyUndefinedVarInTry' => [
'<?php
class Foo {
public static function possiblyThrows(): bool {
$result = (bool)rand(0, 1);
if (!$result) {
throw new \Exception("BOOM");
}
return true;
}
}
try {
$result = Foo::possiblyThrows();
$a = "ACME";
if ($result) {
echo $a;
}
} catch (\Exception $e) {
echo $a;
}',
'error_message' => 'PossiblyUndefinedGlobalVariable',
],
];
}
}

0 comments on commit 94d4b87

Please sign in to comment.
You can’t perform that action at this time.