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:
parent
f011197090
commit
7d17a07cd2
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user