2020-07-08 21:51:02 +02:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Tests;
|
|
|
|
|
2021-12-04 21:55:53 +01:00
|
|
|
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
|
|
|
|
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
|
|
|
|
|
2020-07-08 22:24:20 +02:00
|
|
|
class IfThisIsTest extends TestCase
|
2020-07-08 21:51:02 +02:00
|
|
|
{
|
2021-12-04 21:55:53 +01:00
|
|
|
use ValidCodeAnalysisTestTrait;
|
|
|
|
use InvalidCodeAnalysisTestTrait;
|
2020-07-08 21:51:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return iterable<string,array{string,assertions?:array<string,string>,error_levels?:string[]}>
|
|
|
|
*/
|
2021-09-21 12:21:01 +02:00
|
|
|
public function providerValidCodeParse(): iterable
|
2020-07-08 21:51:02 +02:00
|
|
|
{
|
|
|
|
return [
|
|
|
|
'worksAfterConvert' => [
|
|
|
|
'<?php
|
|
|
|
interface I {
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function test();
|
|
|
|
}
|
|
|
|
|
|
|
|
class F implements I
|
|
|
|
{
|
|
|
|
/**
|
2021-10-28 10:44:37 +02:00
|
|
|
* @psalm-this-out I
|
2020-07-08 21:51:02 +02:00
|
|
|
* @return void
|
|
|
|
*/
|
2020-07-12 22:06:03 +02:00
|
|
|
public function convert() {}
|
2020-07-08 21:51:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @psalm-if-this-is I
|
|
|
|
* @return void
|
|
|
|
*/
|
2020-07-12 22:06:03 +02:00
|
|
|
public function test() {}
|
2020-07-08 21:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$f = new F();
|
|
|
|
$f->convert();
|
|
|
|
$f->test();
|
|
|
|
'
|
2020-07-12 22:06:03 +02:00
|
|
|
],
|
|
|
|
'withTemplate' => [
|
|
|
|
'<?php
|
|
|
|
class Frozen {}
|
|
|
|
class Unfrozen {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @template T of Frozen|Unfrozen
|
|
|
|
*/
|
|
|
|
class Foo
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var T
|
|
|
|
*/
|
|
|
|
private $state;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param T $state
|
|
|
|
*/
|
|
|
|
public function __construct($state)
|
|
|
|
{
|
|
|
|
$this->state = $state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $name
|
|
|
|
* @param mixed $val
|
|
|
|
* @psalm-if-this-is Foo<Unfrozen>
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function set($name, $val)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Foo<Frozen>
|
|
|
|
*/
|
|
|
|
public function freeze()
|
|
|
|
{
|
|
|
|
/** @var Foo<Frozen> */
|
|
|
|
$f = clone $this;
|
|
|
|
return $f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$f = new Foo(new Unfrozen());
|
|
|
|
$f->set("asd", 10);
|
|
|
|
'
|
|
|
|
],
|
|
|
|
'subclass' => [
|
|
|
|
'<?php
|
|
|
|
class G
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @psalm-if-this-is G
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function test() {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class F extends G
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
$f = new F();
|
|
|
|
$f->test();
|
|
|
|
'
|
2020-07-08 21:51:02 +02:00
|
|
|
]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array<string, array{0: string, error_message: string}>
|
|
|
|
*/
|
2021-09-21 12:21:01 +02:00
|
|
|
public function providerInvalidCodeParse(): iterable
|
2020-07-08 21:51:02 +02:00
|
|
|
{
|
|
|
|
return [
|
2021-09-22 10:26:21 +02:00
|
|
|
'failsWithWrongTemplate1' => [
|
2020-07-08 21:51:02 +02:00
|
|
|
'<?php
|
2021-12-04 21:55:53 +01:00
|
|
|
|
2021-09-22 10:26:21 +02:00
|
|
|
/**
|
|
|
|
* @template T
|
|
|
|
*/
|
|
|
|
class a {
|
|
|
|
/**
|
|
|
|
* @var T
|
|
|
|
*/
|
|
|
|
private $data;
|
|
|
|
/**
|
|
|
|
* @param T $data
|
|
|
|
*/
|
|
|
|
public function __construct($data) {
|
|
|
|
$this->data = $data;
|
2020-07-08 21:51:02 +02:00
|
|
|
}
|
2021-09-22 10:26:21 +02:00
|
|
|
/**
|
|
|
|
* @psalm-if-this-is a<int>
|
|
|
|
*/
|
|
|
|
public function test(): void {
|
2020-07-08 21:51:02 +02:00
|
|
|
}
|
2021-09-22 10:26:21 +02:00
|
|
|
}
|
2020-07-08 21:51:02 +02:00
|
|
|
|
2021-09-22 10:26:21 +02:00
|
|
|
$i = new a("test");
|
|
|
|
$i->test();
|
2020-07-08 21:51:02 +02:00
|
|
|
',
|
|
|
|
'error_message' => 'IfThisIsMismatch'
|
2020-07-12 22:06:03 +02:00
|
|
|
],
|
2021-09-22 10:26:21 +02:00
|
|
|
'failsWithWrongTemplate2' => [
|
2020-07-12 22:06:03 +02:00
|
|
|
'<?php
|
|
|
|
class Frozen {}
|
|
|
|
class Unfrozen {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @template T of Frozen|Unfrozen
|
|
|
|
*/
|
|
|
|
class Foo
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var T
|
|
|
|
*/
|
|
|
|
private $state;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param T $state
|
|
|
|
*/
|
|
|
|
public function __construct($state)
|
|
|
|
{
|
|
|
|
$this->state = $state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $name
|
|
|
|
* @param mixed $val
|
|
|
|
* @psalm-if-this-is Foo<Unfrozen>
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function set($name, $val) {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Foo<Frozen>
|
|
|
|
*/
|
|
|
|
public function freeze()
|
|
|
|
{
|
|
|
|
/** @var Foo<Frozen> */
|
|
|
|
$f = clone $this;
|
|
|
|
return $f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$f = new Foo(new Unfrozen());
|
|
|
|
$f->set("asd", 10);
|
|
|
|
$g = $f->freeze();
|
|
|
|
$g->set("asd", 20); // Fails
|
|
|
|
',
|
|
|
|
'error_message' => 'IfThisIsMismatch'
|
|
|
|
],
|
2020-07-08 21:51:02 +02:00
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|