1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-06 05:29:00 +01:00
psalm/tests/TraitTest.php

1253 lines
39 KiB
PHP
Raw Normal View History

2016-12-17 04:16:29 +01:00
<?php
2023-10-19 13:12:06 +02:00
declare(strict_types=1);
2016-12-17 04:16:29 +01:00
namespace Psalm\Tests;
2021-12-04 21:55:53 +01:00
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
use const DIRECTORY_SEPARATOR;
class TraitTest extends TestCase
2016-12-17 04:16:29 +01:00
{
2021-12-04 21:55:53 +01:00
use InvalidCodeAnalysisTestTrait;
use ValidCodeAnalysisTestTrait;
2016-12-17 04:16:29 +01:00
public function providerValidCodeParse(): iterable
2016-12-17 04:16:29 +01:00
{
return [
'accessiblePrivateMethodFromTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
private function fooFoo(): void {
}
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
$this->fooFoo();
}
2017-05-27 02:05:57 +02:00
}',
],
'accessibleProtectedMethodFromTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
protected function fooFoo(): void {
}
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
$this->fooFoo();
}
2017-05-27 02:05:57 +02:00
}',
],
'accessiblePublicMethodFromTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
}
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
$this->fooFoo();
}
2017-05-27 02:05:57 +02:00
}',
],
'accessiblePrivatePropertyFromTrait' => [
'code' => '<?php
trait T {
/** @var string */
private $fooFoo = "";
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
echo $this->fooFoo;
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->fooFoo = "hello";
}
2017-05-27 02:05:57 +02:00
}',
],
'accessibleProtectedPropertyFromTrait' => [
'code' => '<?php
trait T {
/** @var string */
protected $fooFoo = "";
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
echo $this->fooFoo;
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->fooFoo = "hello";
}
2017-05-27 02:05:57 +02:00
}',
],
'accessiblePublicPropertyFromTrait' => [
'code' => '<?php
trait T {
/** @var string */
public $fooFoo = "";
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
echo $this->fooFoo;
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->fooFoo = "hello";
}
2017-05-27 02:05:57 +02:00
}',
],
'accessibleProtectedMethodFromInheritedTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
protected function fooFoo(): void {
}
}
class B {
use T;
}
class C extends B {
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
$this->fooFoo();
}
2017-05-27 02:05:57 +02:00
}',
],
'accessiblePublicMethodFromInheritedTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
}
}
class B {
use T;
}
class C extends B {
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
$this->fooFoo();
}
2017-05-27 02:05:57 +02:00
}',
],
'staticClassMethodFromWithinTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
self::barBar();
}
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public static function barBar(): void {
}
2017-05-27 02:05:57 +02:00
}',
],
'redefinedTraitMethodWithoutAlias' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
}
}
class B {
use T;
2018-01-11 21:50:45 +01:00
public function fooFoo(string $a): void {
}
}
2017-05-27 02:05:57 +02:00
(new B)->fooFoo("hello");',
],
'redefinedTraitMethodWithAlias' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
}
}
class B {
use T {
fooFoo as barBar;
}
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
$this->barBar();
}
2017-05-27 02:05:57 +02:00
}',
],
'traitSelf' => [
'code' => '<?php
trait T {
public function g(): self
{
return $this;
}
}
class A {
use T;
}
$a = (new A)->g();',
'assertions' => [
2017-06-29 16:22:49 +02:00
'$a' => 'A',
2017-05-27 02:05:57 +02:00
],
],
'parentTraitSelf' => [
'code' => '<?php
trait T {
public function g(): self
{
return $this;
}
}
class A {
use T;
}
class B extends A {
}
class C {
use T;
}
$a = (new B)->g();',
'assertions' => [
2017-06-29 16:22:49 +02:00
'$a' => 'A',
2017-05-27 02:05:57 +02:00
],
],
'directStaticCall' => [
'code' => '<?php
trait T {
/** @return void */
public static function foo() {}
}
class A {
use T;
/** @return void */
public function bar() {
T::foo();
}
2017-05-27 02:05:57 +02:00
}',
],
'abstractTraitMethod' => [
'code' => '<?php
trait T {
/** @return void */
abstract public function foo();
}
abstract class A {
use T;
/** @return void */
public function bar() {
$this->foo();
}
2017-05-27 02:05:57 +02:00
}',
],
'instanceOfTraitUser' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function f(): void {
if ($this instanceof A) { }
}
}
class A {
use T;
}
class B {
use T;
}',
],
'getClassTraitUser' => [
'code' => '<?php
trait T {
public function f(): void {
if (get_class($this) === B::class) {
$this->foo();
}
}
}
class A {
use T;
}
class B {
use T;
public function foo() : void {}
}',
],
'staticClassTraitUser' => [
'code' => '<?php
trait T {
public function f(): void {
if (static::class === B::class) {
$this->foo();
}
}
}
class A {
use T;
}
class B {
use T;
public function foo() : void {}
}',
],
'isAClassTraitUserStringClass' => [
'code' => '<?php
trait T {
public function f(): void {
2021-10-12 20:13:04 +02:00
if (is_a(static::class, B::class, true)) { }
}
}
class A {
use T;
}
class B {
use T;
public function foo() : void {}
}',
],
'isAClassTraitUserClassConstant' => [
'code' => '<?php
trait T {
public function f(): void {
2021-10-12 20:13:04 +02:00
if (is_a(static::class, B::class, true)) { }
}
}
class A {
use T;
}
class B {
use T;
public function foo() : void {}
}',
],
'useTraitInClassWithAbstractMethod' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
abstract public function foo(): void;
}
class A {
2018-01-11 21:50:45 +01:00
public function foo(): void {}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}',
],
'useTraitInSubclassWithAbstractMethod' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
abstract public function foo(): void;
}
abstract class A {
2018-01-11 21:50:45 +01:00
public function foo(): void {}
}
class B extends A {
use T;
}',
],
'useTraitInSubclassWithAbstractMethodInParent' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function foo(): void {}
}
abstract class A {
2018-01-11 21:50:45 +01:00
abstract public function foo(): void {}
}
class B extends A {
use T;
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}',
],
'differentMethodReturnTypes' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public static function getSelf(): self {
return new self();
}
2018-01-11 21:50:45 +01:00
public static function callGetSelf(): self {
return self::getSelf();
}
}
class A {
use T;
}
class B {
use T;
}',
],
'parentRefInTraitShouldNotFail' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
public function foo(): void {
parent::foo();
}
}
class A {
2018-01-11 21:50:45 +01:00
public function foo(): void {}
}
class B extends A {
use T;
}',
],
2018-01-21 06:32:45 +01:00
'namespacedTraitLookup' => [
'code' => '<?php
2018-01-21 06:32:45 +01:00
namespace Classes {
use Traits\T;
class A {}
class B {
use T;
}
}
namespace Traits {
use Classes\A;
trait T {
public function getA() : A {
return new A;
}
}
}
namespace {
$a = (new Classes\B)->getA();
}',
],
'useAndMap' => [
'code' => '<?php
class C
{
use T2;
2020-03-03 05:07:21 +01:00
use T1 {
2020-03-03 05:07:21 +01:00
traitFunc as aliasedTraitFunc;
}
public static function func(): void
{
2020-03-03 05:07:21 +01:00
static::aliasedTraitFunc();
}
}
trait T1
{
public static function traitFunc(): void {}
}
trait T2 { }',
],
'mapAndUse' => [
'code' => '<?php
class C
{
use T1 {
traitFunc as _func;
}
use T2;
public static function func(): void
{
static::_func();
}
}
trait T1
{
public static function traitFunc(): void {}
}
trait T2 { }',
],
'moreArgsInDefined' => [
'code' => '<?php
trait T {
abstract public function foo() : void;
public function callFoo() : void {
$this->foo();
}
}
class A {
use T;
public function foo(string $s = null) : void {
}
}',
],
2018-03-21 21:55:31 +01:00
'aliasedMethodInternalCallNoReplacement' => [
'code' => '<?php
2018-03-21 21:55:31 +01:00
trait T {
public function foo() : int {
return $this->bar();
}
public function bar() : int {
return 3;
}
}
class A {
use T {
bar as bat;
}
public function baz() : int {
return $this->bar();
}
}',
],
'aliasedMethodInternalCallWithLocalDefinition' => [
'code' => '<?php
2018-03-21 21:55:31 +01:00
trait T {
public function bar() : int {
return 3;
}
}
class A {
use T {
bar as bat;
}
public function bar() : string {
return "hello";
}
public function baz() : string {
return $this->bar();
}
}',
],
'allMethodsReplaced' => [
'code' => '<?php
trait T {
protected function foo() : void {}
public function bat() : void {
$this->foo();
}
}
class C {
use T;
protected function foo(string $s) : void {}
public function bat() : void {
$this->foo("bat");
}
}',
],
2018-03-21 22:39:01 +01:00
'aliasedPrivateMethodInternalCallWithLocalDefinition' => [
'code' => '<?php
2018-03-21 22:39:01 +01:00
trait T1 {
use T2;
private function foo() : int {
return $this->bar();
}
}
trait T2 {
private function bar() : int {
return 3;
}
}
class A {
use T1;
private function baz() : int {
return $this->bar();
}
}',
],
2018-05-09 04:32:57 +02:00
'traitClassConst' => [
'code' => '<?php
2018-05-09 04:32:57 +02:00
trait A {
public function foo(): string {
return B::class;
}
}
trait B {}
class C {
use A;
2019-03-23 19:27:54 +01:00
}',
2018-05-09 04:32:57 +02:00
],
'noRedundantConditionForTraitStatic' => [
'code' => '<?php
trait Foo {
public function bar() : array {
$type = static::class;
$r = new \ReflectionClass($type);
$values = $r->getConstants();
$callback =
/** @param mixed $v */
function ($v) : bool {
return \is_int($v) || \is_string($v);
};
if (is_a($type, \Bat::class, true)) {
$callback =
/** @param mixed $v */
function ($v) : bool {
return \is_int($v) && 0 === ($v & $v - 1) && $v > 0;
};
}
return array_filter($values, $callback);
}
}
class Bar {
use Foo;
}
class Bat {
use Foo;
2019-03-23 19:27:54 +01:00
}',
],
'nonMemoizedAssertions' => [
'code' => '<?php
trait T {
public function compare(O $other) : void {
if ($other instanceof self) {
if ($other->value === $this->value) {}
}
}
}
class O {}
class A extends O {
use T;
/** @var string */
private $value;
public function __construct(string $string) {
$this->value = $string;
}
}
class B extends O {
use T;
/** @var bool */
private $value;
public function __construct(bool $bool) {
$this->value = $bool;
}
2019-03-23 19:27:54 +01:00
}',
],
'manyTraitAliases' => [
'code' => '<?php
trait Foo {
public static function staticMethod():void {}
public function nonstatic():void {}
}
Class Bar {
use Foo {
Foo::staticMethod as foo;
Foo::staticMethod as foobar;
Foo::staticMethod as fine;
Foo::nonstatic as bad;
Foo::nonstatic as good;
}
}
$b = new Bar();
Bar::fine();
$b::fine();
$b->fine();
$b->good();
Bar::foo();
Bar::foobar();
$b::foo();
$b::foobar();
$b->foo();
$b->foobar();
2019-03-23 19:27:54 +01:00
$b->bad();',
],
'inheritedProtectedTraitMethodAccess' => [
'code' => '<?php
trait T {
private function bar() : void {}
}
class A {
use T {
bar as protected;
}
}
class AChild extends A {
public function foo() : void {
$this->bar();
}
2019-03-23 19:27:54 +01:00
}',
],
'inheritedPublicTraitMethodAccess' => [
'code' => '<?php
trait T {
private function bar() : void {}
}
class A {
use T {
bar as public;
}
}
2019-03-23 19:27:54 +01:00
(new A)->bar();',
],
'allowImplementMethodMadePublicInClass' => [
'code' => '<?php
interface I {
public function boo() : void;
}
trait T {
private function boo() : void {}
}
class A implements I {
use T { boo as public; }
}',
],
'allowImplementMethodMadePublicInParent' => [
'code' => '<?php
interface I {
public function boo() : void;
}
trait T {
private function boo() : void {}
}
class B {
use T { boo as public; }
}
class BChild extends B implements I {}',
],
'allowTraitParentDefinition' => [
'code' => '<?php
class A {}
class C extends A
{
use T;
}
trait T
{
public function bar() : ?C
{
if ($this instanceof A) {
return $this;
}
return null;
}
2019-03-23 19:27:54 +01:00
}',
],
'noCrashOnUndefinedIgnoredTrait' => [
'code' => '<?php
/** @psalm-suppress UndefinedTrait */
class C {
use UnknownTrait;
2019-03-23 19:27:54 +01:00
}',
],
'reconcileStaticTraitProperties' => [
'code' => '<?php
trait T {
/**
* @var string|null
*/
private static $b;
private static function booA(): string {
if (self::$b === null) {
return "hello";
}
return self::$b;
}
}
class C {
use T;
}',
],
'covariantAbstractReturn' => [
'code' => '<?php
trait T {
/** @return iterable */
abstract public function bar();
}
class C {
use T;
/** @return array */
public function bar() { return []; }
2019-03-23 19:27:54 +01:00
}',
],
'traitSelfParam' => [
'code' => '<?php
trait T {
public function bar(self $object): self {
return $this;
}
}
class Foo {
use T;
}
$f1 = new Foo();
$f2 = (new Foo())->bar($f1);',
],
'traitSelfDocblockReturn' => [
'code' => '<?php
trait T {
/** @return self */
public function getSelf() {
return $this;
}
}
class C {
use T;
2019-07-05 22:24:00 +02:00
}',
],
'abstractThisMethod' => [
'code' => '<?php
trait ATrait {
/** @return $this */
abstract public function bar();
}
class C {
use ATrait;
/** @return $this */
public function bar() {
return $this;
}
2022-12-18 17:15:15 +01:00
}',
],
'classAliasedTrait' => [
'code' => '<?php
trait FeatureV1 {}
class_alias(FeatureV1::class, Feature::class);
class Application {
use Feature;
}',
],
'renameMethodNoCrash' => [
'code' => '<?php
trait HelloTrait {
protected function sayHello() : string {
return "Hello";
}
}
class Person {
use HelloTrait {
2020-04-28 15:17:31 +02:00
sayHello as originalSayHello;
}
protected function sayHello() : string {
2020-04-28 15:17:31 +02:00
return $this->originalSayHello();
}
}
class BrokenPerson extends Person {
2020-04-28 15:17:31 +02:00
protected function originalSayHello() : string {
return "bad";
}
}',
],
'instanceofStaticInsideTrait' => [
'code' => '<?php
trait T {
/**
* @param mixed $instance
* @return ?static
*/
public static function filterInstance($instance) {
return $instance instanceof static ? $instance : null;
}
}
class A {
use T;
2022-12-18 17:15:15 +01:00
}',
],
'propertyNotDefinedInTrait' => [
'code' => '<?php
class A1 {
use A2;
public static string $titlefield = "blah";
}
trait A2 {
public static function test() : string {
/**
* @var string
*/
$sortfield = (isset(static::$sortfield)) ?
static::$sortfield
: static::$titlefield;
return $sortfield;
}
2022-12-18 17:15:15 +01:00
}',
],
'staticNotBoundInFinal' => [
'code' => '<?php
trait Foo {
/**
* @return static
*/
final public function foo(): self
{
return $this;
}
}
class A {
use Foo;
2022-12-18 17:15:15 +01:00
}',
],
'staticReturnWithFinal' => [
'code' => '<?php
trait T {
/** @return static */
public function instance() {
return new static();
}
}
final class A {
use T;
2022-12-18 17:15:15 +01:00
}',
],
2022-02-24 01:50:05 +01:00
'suppressIssueOnTrait' => [
2022-02-26 21:28:15 +01:00
'code' => '<?php
2022-02-24 01:50:05 +01:00
/** @psalm-suppress InvalidAttribute */
#[Attribute]
trait Foo {}',
],
'noCrashOnConditionalTrait' => [
'code' => '<?php
namespace NS;
if (rand(0, 1)) {
trait T {}
}
2022-12-18 17:15:15 +01:00
',
],
2023-01-17 15:25:45 +01:00
'constant in trait' => [
'code' => <<<'PHP'
<?php
trait TraitA {
public const PUBLIC_CONST = 'PUBLIC_CONST';
protected const PROTECTED_CONST = 'PROTECTED_CONST';
private const PRIVATE_CONST = 'PRIVATE_CONST';
}
class ClassB {
use TraitA;
public static function getPublicConst(): string { return self::PUBLIC_CONST; }
public static function getProtectedConst(): string { return self::PROTECTED_CONST; }
public static function getPrivateConst(): string { return self::PRIVATE_CONST; }
}
class ClassC extends ClassB {
public static function getPublicConst(): string { return self::PUBLIC_CONST; }
public static function getProtectedConst(): string { return self::PROTECTED_CONST; }
}
PHP,
'assertions' => [],
'ignored_issues' => [],
'php_version' => '8.2',
],
'constant in trait with alias' => [
'code' => <<<'PHP'
<?php
trait TraitA { private const PRIVATE_CONST = 'PRIVATE_CONST'; }
class ClassB { use TraitA { PRIVATE_CONST as public PUBLIC_CONST; } }
$c = ClassB::PUBLIC_CONST;
PHP,
'assertions' => ['$c' => 'string'],
'ignored_issues' => [],
'php_version' => '8.2',
],
];
2016-12-17 04:16:29 +01:00
}
public function providerInvalidCodeParse(): iterable
2016-12-17 04:16:29 +01:00
{
return [
'inaccessiblePrivateMethodFromInheritedTrait' => [
'code' => '<?php
trait T {
2018-01-11 21:50:45 +01:00
private function fooFoo(): void {
}
}
class B {
use T;
}
class C extends B {
2018-01-11 21:50:45 +01:00
public function doFoo(): void {
$this->fooFoo();
}
}',
2017-05-27 02:05:57 +02:00
'error_message' => 'InaccessibleMethod',
],
'undefinedTrait' => [
'code' => '<?php
class B {
use A;
}',
2017-05-27 02:05:57 +02:00
'error_message' => 'UndefinedTrait',
],
'missingPropertyType' => [
'code' => '<?php
trait T {
public $foo = null;
}
class A {
use T;
2018-01-11 21:50:45 +01:00
public function assignToFoo(): void {
$this->foo = 5;
}
}',
2019-02-27 22:00:44 +01:00
'error_message' => 'MissingPropertyType - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:32 - Property T::$foo does not have a ' .
'declared type - consider int|null',
],
'missingPropertyTypeWithConstructorInit' => [
'code' => '<?php
trait T {
public $foo;
}
class A {
use T;
2018-04-21 23:20:21 +02:00
public function __construct() {
$this->foo = 5;
}
}',
2019-02-27 22:00:44 +01:00
'error_message' => 'MissingPropertyType - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:32 - Property T::$foo does not have a ' .
2017-05-27 02:05:57 +02:00
'declared type - consider int',
],
'missingPropertyTypeWithConstructorInitAndNull' => [
'code' => '<?php
trait T {
public $foo;
}
class A {
use T;
2018-04-21 23:20:21 +02:00
public function __construct() {
$this->foo = 5;
}
2018-01-11 21:50:45 +01:00
public function makeNull(): void {
$this->foo = null;
}
}',
2019-02-27 22:00:44 +01:00
'error_message' => 'MissingPropertyType - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:32 - Property T::$foo does not have a ' .
'declared type - consider int|null',
],
'missingPropertyTypeWithConstructorInitAndNullDefault' => [
'code' => '<?php
trait T {
public $foo = null;
}
class A {
use T;
2018-04-21 23:20:21 +02:00
public function __construct() {
$this->foo = 5;
}
}',
2019-02-27 22:00:44 +01:00
'error_message' => 'MissingPropertyType - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:32 - Property T::$foo does not have a ' .
'declared type - consider int|null',
2017-05-27 02:05:57 +02:00
],
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
'redefinedTraitMethodInSubclass' => [
'code' => '<?php
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
trait T {
2018-01-11 21:50:45 +01:00
public function fooFoo(): void {
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
}
class B {
use T;
}
class C extends B {
2018-01-11 21:50:45 +01:00
public function fooFoo(string $a): void {
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
}',
'error_message' => 'MethodSignatureMismatch',
],
'missingTraitPropertyType' => [
'code' => '<?php
trait T {
public $foo = 5;
}
class A {
use T;
}',
'error_message' => 'MissingPropertyType',
],
'nestedTraitWithBadReturnType' => [
'code' => '<?php
trait A {
public function foo() : string {
return 5;
}
}
trait B {
use A;
}
class C {
use B;
}',
'error_message' => 'InvalidReturnType',
],
'replaceTraitMethod' => [
'code' => '<?php
trait T {
protected function foo() : void {}
public function bat() : void {
$this->foo();
}
}
class C {
use T;
protected function foo(string $s) : void {}
}',
'error_message' => 'TooFewArguments',
],
'traitMethodMadePrivate' => [
'code' => '<?php
trait T {
public function foo() : void {
echo "here";
}
}
class C {
use T {
foo as private traitFoo;
}
public function bar() : void {
$this->traitFoo();
}
}
class D extends C {
public function bar() : void {
$this->traitFoo(); // should fail
}
}',
2019-03-23 19:27:54 +01:00
'error_message' => 'InaccessibleMethod',
],
'preventTraitPropertyType' => [
'code' => '<?php
trait T {}
class X {
/** @var T|null */
public $hm;
}',
'error_message' => 'UndefinedDocblockClass',
],
2023-01-17 15:25:45 +01:00
'constant declaration in trait, php <8.2.0' => [
'code' => <<<'PHP'
<?php
trait A { const B = 0; }
PHP,
2023-03-03 09:25:27 +01:00
'error_message' => 'ConstantDeclarationInTrait',
2023-01-17 15:25:45 +01:00
'ignored_issues' => [],
'php_version' => '8.1',
],
'duplicateTraitProperty' => [
'code' => '<?php
trait T {
public mixed $foo = 5;
protected static mixed $foo;
}
',
'error_message' => 'DuplicateProperty',
],
];
}
2016-12-17 04:16:29 +01:00
}