diff --git a/src/Psalm/Checker/FunctionLikeChecker.php b/src/Psalm/Checker/FunctionLikeChecker.php index 4f812d4ab..706792fef 100644 --- a/src/Psalm/Checker/FunctionLikeChecker.php +++ b/src/Psalm/Checker/FunctionLikeChecker.php @@ -314,7 +314,13 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo public function getMethodId() { if ($this->function instanceof ClassMethod) { - return $this->fq_class_name . '::' . strtolower($this->function->name); + $function_name = $this->function->name; + + if (strtolower($function_name) === strtolower($this->class_name)) { + $function_name = '__construct'; + } + + return $this->fq_class_name . '::' . strtolower($function_name); } if ($this->function instanceof Function_) { diff --git a/src/Psalm/Checker/MethodChecker.php b/src/Psalm/Checker/MethodChecker.php index 97055a261..5b22868ba 100644 --- a/src/Psalm/Checker/MethodChecker.php +++ b/src/Psalm/Checker/MethodChecker.php @@ -172,8 +172,14 @@ class MethodChecker extends FunctionLikeChecker */ public static function extractReflectionMethodInfo(\ReflectionMethod $method) { - $method_id = $method->class . '::' . strtolower((string)$method->name); - self::$cased_method_ids[$method_id] = $method->class . '::' . $method->name; + if (strtolower($method->name) === strtolower((string)$method->class)) { + $method_id = $method->class . '::__construct'; + self::$cased_method_ids[$method_id] = $method->class . '::__construct'; + } + else { + $method_id = $method->class . '::' . strtolower($method->name); + self::$cased_method_ids[$method_id] = $method->class . '::' . $method->name; + } if (isset(self::$have_reflected[$method_id])) { return null; @@ -255,7 +261,13 @@ class MethodChecker extends FunctionLikeChecker */ protected function registerMethod(PhpParser\Node\Stmt\ClassMethod $method) { - $method_id = $this->fq_class_name . '::' . strtolower($method->name); + if (strtolower($method->name) === strtolower((string)$this->class_name)) { + $method_id = $this->fq_class_name . '::__construct'; + } + else { + $method_id = $this->fq_class_name . '::' . strtolower($method->name); + } + $cased_method_id = self::$cased_method_ids[$method_id] = $this->fq_class_name . '::' . $method->name; if (isset(self::$have_reflected[$method_id]) || isset(self::$have_registered[$method_id])) { @@ -459,15 +471,19 @@ class MethodChecker extends FunctionLikeChecker self::registerClassMethod($method_id); + $old_method_id = null; + if (isset(self::$declaring_methods[$method_id])) { return true; } + // support checking oldstyle constructors if ($method_parts[1] === '__construct') { - // @todo ? + $old_constructor_name = array_pop(explode('\\', $method_parts[0])); + $old_method_id = $method_parts[0] . '::' . $old_constructor_name; } - if (FunctionChecker::inCallMap($method_id)) { + if (FunctionChecker::inCallMap($method_id) || ($old_method_id && FunctionChecker::inCallMap($method_id))) { return true; } diff --git a/tests/Php40Test.php b/tests/Php40Test.php new file mode 100644 index 000000000..6fba8687d --- /dev/null +++ b/tests/Php40Test.php @@ -0,0 +1,48 @@ +create(ParserFactory::PREFER_PHP7); + + $config = Config::getInstance(); + $config->throw_exception = true; + $config->use_docblock_types = true; + } + + public function setUp() + { + FileChecker::clearCache(); + } + + public function testExtendOldStyleConstructor() + { + $stmts = self::$parser->parse('check(true, true, $context); + } +}