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

# This is a combination of 4 commits.

# The first commit's message is:
Make cofig schema more relaxed about ordering

# This is the 2nd commit message:

Add tests for awkward case

# This is the 3rd commit message:

Fix static calls to class methods within traits

# This is the 4th commit message:

Repopulate fewer arrays
This commit is contained in:
Matthew Brown 2016-12-29 23:37:09 -05:00
parent 2709198392
commit 3e78405836
5 changed files with 90 additions and 16 deletions

View File

@ -3,13 +3,13 @@
<xs:element name="psalm" type="PsalmType" />
<xs:complexType name="PsalmType">
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element name="projectFiles" type="ProjectFilesType" minOccurs="1" maxOccurs="1" />
<xs:element name="fileExtensions" type="FileExtensionsType" minOccurs="0" maxOccurs="1" />
<xs:element name="mockClasses" type="MockClassesType" minOccurs="0" maxOccurs="1" />
<xs:element name="plugins" type="PluginsType" minOccurs="0" maxOccurs="1" />
<xs:element name="issueHandlers" type="IssueHandlersType" minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="stopOnFirstError" type="xs:string" />
@ -45,7 +45,7 @@
<xs:complexType name="FileExtensionsType">
<xs:sequence>
<xs:element name="extension">
<xs:element name="extension" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="filetypeHandler" type="xs:string" />

View File

@ -262,7 +262,6 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
$config = Config::getInstance();
self::$registered_classes[$this->fq_class_name] = true;
self::$user_defined[$this->fq_class_name] = true;
$leftover_stmts = [];
@ -272,20 +271,25 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
$long_file_name = Config::getInstance()->getBaseDir() . $this->file_name;
self::$public_class_methods[$this->fq_class_name] = [];
self::$protected_class_methods[$this->fq_class_name] = [];
self::$public_class_properties[$this->fq_class_name] = [];
self::$protected_class_properties[$this->fq_class_name] = [];
self::$private_class_properties[$this->fq_class_name] = [];
if (!isset(self::$registered_classes[$this->fq_class_name])) {
self::$public_class_methods[$this->fq_class_name] = [];
self::$protected_class_methods[$this->fq_class_name] = [];
self::$public_static_class_properties[$this->fq_class_name] = [];
self::$protected_static_class_properties[$this->fq_class_name] = [];
self::$private_static_class_properties[$this->fq_class_name] = [];
self::$public_class_properties[$this->fq_class_name] = [];
self::$protected_class_properties[$this->fq_class_name] = [];
self::$private_class_properties[$this->fq_class_name] = [];
self::$public_class_constants[$this->fq_class_name] = [];
self::$protected_class_constants[$this->fq_class_name] = [];
self::$private_class_constants[$this->fq_class_name] = [];
self::$public_static_class_properties[$this->fq_class_name] = [];
self::$protected_static_class_properties[$this->fq_class_name] = [];
self::$private_static_class_properties[$this->fq_class_name] = [];
self::$public_class_constants[$this->fq_class_name] = [];
self::$protected_class_constants[$this->fq_class_name] = [];
self::$private_class_constants[$this->fq_class_name] = [];
}
self::$registered_classes[$this->fq_class_name] = true;
if (!$class_context) {
$class_context = new Context($this->file_name, $this->fq_class_name);

View File

@ -599,7 +599,7 @@ class CallChecker
? $statements_checker->getNamespace() . '\\'
: '';
$fq_class_name = $namespace . $statements_checker->getClassName();
$fq_class_name = $context->self ?: $namespace . $statements_checker->getClassName();
}
if ($context->isPhantomClass($fq_class_name)) {

View File

@ -223,6 +223,54 @@ class InterfaceTest extends PHPUnit_Framework_TestCase
$file_checker->check(true, true, $context);
}
public function testCorrectInterfaceMethodSignature()
{
$stmts = self::$parser->parse('<?php
interface A {
public function foo(int $a) : void;
}
class B implements A {
public function foo(int $a) : void {
}
}
?>
');
$file_checker = new FileChecker('somefile.php', $stmts);
$context = new Context('somefile.php');
$file_checker->check(true, true, $context);
}
public function testInterfaceMethodImplementedInParentAndTrait()
{
$stmts = self::$parser->parse('<?php
interface MyInterface {
public function foo(int $a) : void;
}
trait T {
}
class B {
public function foo(int $a) : void {
}
}
class C extends B implements MyInterface {
use T;
}
?>
');
$file_checker = new FileChecker('somefile.php', $stmts);
$context = new Context('somefile.php');
$file_checker->check(true, true, $context);
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage MethodSignatureMismatch

View File

@ -159,6 +159,28 @@ class TraitTest extends PHPUnit_Framework_TestCase
$file_checker->check();
}
public function testStaticClassMethodFromWithinTrait()
{
$stmts = self::$parser->parse('<?php
trait A {
public function foo() : void {
self::bar();
}
}
class B {
use A;
public static function bar() : void {
}
}
');
$file_checker = new FileChecker('somefile.php', $stmts);
$file_checker->check();
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage UndefinedTrait