From 11bfaaa5f7afed8b06f7830c940f71e43992001d Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Wed, 9 Jan 2019 08:35:53 -0500 Subject: [PATCH] Prevent crash in constructor checks --- .../Statements/Expression/CallAnalyzer.php | 40 +++++++++++++++++- tests/PropertyTypeTest.php | 42 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php index 96d7777f3..6221489b0 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php @@ -102,7 +102,45 @@ class CallAnalyzer ) { $method_id = $fq_class_name . '::' . strtolower($method_name); - $declaring_method_id = (string) $codebase->methods->getDeclaringMethodId($method_id); + $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); + + if (!$declaring_method_id) { + if (isset($context->vars_in_scope['$this'])) { + foreach ($context->vars_in_scope['$this']->getTypes() as $atomic_type) { + if ($atomic_type instanceof TNamedObject) { + $fq_class_name = $atomic_type->value; + $method_id = $fq_class_name . '::' . strtolower($method_name); + + $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); + + if ($declaring_method_id) { + break; + } + + if (!$atomic_type->extra_types) { + continue; + } + + foreach ($atomic_type->extra_types as $intersection_type) { + if ($intersection_type instanceof TNamedObject) { + $fq_class_name = $intersection_type->value; + $method_id = $fq_class_name . '::' . strtolower($method_name); + + $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id); + + if ($declaring_method_id) { + break; + } + } + } + } + } + } + + if (!$declaring_method_id) { + throw new \UnexpectedValueException('Could not find declaring method for ' . $method_id); + } + } if (isset($context->initialized_methods[$declaring_method_id])) { return; diff --git a/tests/PropertyTypeTest.php b/tests/PropertyTypeTest.php index 8ee8fb5ff..4cf0ebc4f 100644 --- a/tests/PropertyTypeTest.php +++ b/tests/PropertyTypeTest.php @@ -1132,6 +1132,48 @@ class PropertyTypeTest extends TestCase class B extends A {}', ], + 'noCrashForAbstractConstructorWithInstanceofInterface' => [ + 'a = $this->bar(); + } else { + $this->a = 6; + } + } + } + + interface I { + public function bar() : int; + }', + ], + 'SKIPPED-abstractConstructorWithInstanceofClass' => [ + 'a = $this->bar(); + } else { + $this->a = 6; + } + } + } + + class B extends A { + public function bar() : int { + return 3; + } + }', + [], + 'error_levels' => [] + ], ]; }