1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Fix #125 - allow abstract classes to reference methods only defined in interfaces

This commit is contained in:
Matthew Brown 2017-04-07 19:16:25 -04:00
parent f011197090
commit 7d17a07cd2
2 changed files with 55 additions and 2 deletions

View File

@ -353,6 +353,10 @@ class MethodChecker extends FunctionLikeChecker
return true;
}
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) {
return true;
}
// support checking oldstyle constructors
if ($method_name === '__construct') {
$method_name_parts = explode('\\', $fq_class_name);
@ -550,8 +554,14 @@ class MethodChecker extends FunctionLikeChecker
throw new \UnexpectedValueException('$storage should not be null for ' . $fq_class_name);
}
if (isset(ClassLikeChecker::$storage[$fq_class_name]->declaring_method_ids[$method_name])) {
return ClassLikeChecker::$storage[$fq_class_name]->declaring_method_ids[$method_name];
$class_storage = ClassLikeChecker::$storage[$fq_class_name];
if (isset($class_storage->declaring_method_ids[$method_name])) {
return $class_storage->declaring_method_ids[$method_name];
}
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) {
return $class_storage->overridden_method_ids[$method_name][0];
}
}

View File

@ -452,6 +452,49 @@ class InterfaceTest extends PHPUnit_Framework_TestCase
$file_checker->visitAndAnalyzeMethods($context);
}
/**
* @return void
*/
public function testAbstractInterfaceImplementsButCallMethod()
{
$stmts = self::$parser->parse('<?php
interface I {
public function foo();
}
abstract class A implements I {
public function bar() : void {
$this->foo();
}
}
');
$file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts);
$context = new Context();
$file_checker->visitAndAnalyzeMethods($context);
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage UndefinedMethod
* @return void
*/
public function testAbstractInterfaceImplementsButCallUndefinedMethod()
{
$stmts = self::$parser->parse('<?php
interface I {
public function foo();
}
abstract class A implements I {
public function bar() : void {
$this->foo2();
}
}
');
$file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts);
$context = new Context();
$file_checker->visitAndAnalyzeMethods($context);
}
/**
* @return void