2018-06-30 21:29:37 +02:00
|
|
|
<?php
|
2021-12-15 04:58:32 +01:00
|
|
|
|
2018-06-30 21:29:37 +02:00
|
|
|
namespace Psalm\Tests;
|
|
|
|
|
2021-06-08 04:55:21 +02:00
|
|
|
use Psalm\Config;
|
|
|
|
use Psalm\Context;
|
2021-12-03 20:29:06 +01:00
|
|
|
use Psalm\Exception\CodeException;
|
|
|
|
use Psalm\Exception\ConfigException;
|
|
|
|
use Psalm\Exception\InvalidClasslikeOverrideException;
|
|
|
|
use Psalm\Exception\InvalidMethodOverrideException;
|
2021-12-03 20:11:20 +01:00
|
|
|
use Psalm\Internal\Analyzer\ProjectAnalyzer;
|
2021-06-08 04:55:21 +02:00
|
|
|
use Psalm\Internal\IncludeCollector;
|
2021-07-02 01:10:21 +02:00
|
|
|
use Psalm\Internal\Provider\FakeFileProvider;
|
2021-12-03 20:11:20 +01:00
|
|
|
use Psalm\Internal\Provider\Providers;
|
2021-06-08 04:55:21 +02:00
|
|
|
use Psalm\Internal\RuntimeCaches;
|
2021-12-04 21:55:53 +01:00
|
|
|
use Psalm\Tests\Internal\Provider\FakeParserCacheProvider;
|
2021-06-08 04:55:21 +02:00
|
|
|
|
2019-07-05 22:24:00 +02:00
|
|
|
use function define;
|
|
|
|
use function defined;
|
|
|
|
use function dirname;
|
2021-06-08 04:55:21 +02:00
|
|
|
use function explode;
|
2019-07-05 22:24:00 +02:00
|
|
|
use function getcwd;
|
2020-02-27 21:20:24 +01:00
|
|
|
use function implode;
|
2021-12-03 21:07:25 +01:00
|
|
|
use function reset;
|
2022-11-27 10:19:05 +01:00
|
|
|
use function strlen;
|
|
|
|
use function strpos;
|
|
|
|
use function substr;
|
2021-06-08 04:55:21 +02:00
|
|
|
|
2020-02-27 21:20:24 +01:00
|
|
|
use const DIRECTORY_SEPARATOR;
|
2018-06-30 21:29:37 +02:00
|
|
|
|
|
|
|
class StubTest extends TestCase
|
|
|
|
{
|
2022-12-16 19:58:47 +01:00
|
|
|
protected static TestConfig $config;
|
2018-06-30 21:29:37 +02:00
|
|
|
|
2021-12-05 18:51:26 +01:00
|
|
|
public static function setUpBeforeClass(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
|
|
|
self::$config = new TestConfig();
|
|
|
|
|
|
|
|
if (!defined('PSALM_VERSION')) {
|
2021-05-17 15:27:08 +02:00
|
|
|
define('PSALM_VERSION', '4.0.0');
|
2018-06-30 21:29:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!defined('PHP_PARSER_VERSION')) {
|
|
|
|
define('PHP_PARSER_VERSION', '4.0.0');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 18:51:26 +01:00
|
|
|
public function setUp(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2020-08-23 16:32:07 +02:00
|
|
|
RuntimeCaches::clearAll();
|
2021-07-02 01:10:21 +02:00
|
|
|
$this->file_provider = new FakeFileProvider();
|
2018-06-30 21:29:37 +02:00
|
|
|
}
|
|
|
|
|
2021-12-03 20:11:20 +01:00
|
|
|
private function getProjectAnalyzerWithConfig(Config $config): ProjectAnalyzer
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2021-12-03 20:11:20 +01:00
|
|
|
$project_analyzer = new ProjectAnalyzer(
|
2018-06-30 21:29:37 +02:00
|
|
|
$config,
|
2021-12-03 20:11:20 +01:00
|
|
|
new Providers(
|
2018-09-28 22:18:45 +02:00
|
|
|
$this->file_provider,
|
2022-12-18 17:15:15 +01:00
|
|
|
new FakeParserCacheProvider(),
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
2021-11-27 01:06:33 +01:00
|
|
|
$project_analyzer->setPhpVersion('7.4', 'tests');
|
2018-07-03 17:17:52 +02:00
|
|
|
|
2020-07-11 23:17:22 +02:00
|
|
|
$config->setIncludeCollector(new IncludeCollector());
|
2019-05-30 16:30:41 +02:00
|
|
|
$config->visitComposerAutoloadFiles($project_analyzer, null);
|
2018-07-03 17:17:52 +02:00
|
|
|
|
2018-11-11 18:01:14 +01:00
|
|
|
return $project_analyzer;
|
2018-06-30 21:29:37 +02:00
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testNonexistentStubFile(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(ConfigException::class);
|
2019-05-17 00:36:36 +02:00
|
|
|
$this->expectExceptionMessage('Cannot resolve stubfile path');
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
Config::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="stubs/invalidfile.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileClass(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/systemclass.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2019-03-25 05:07:32 +01:00
|
|
|
namespace A\B\C;
|
2018-06-30 21:29:37 +02:00
|
|
|
|
2019-03-25 05:07:32 +01:00
|
|
|
$a = new \SystemClass();
|
2018-06-30 21:29:37 +02:00
|
|
|
$b = $a->foo(5, "hello");
|
2019-03-25 05:07:32 +01:00
|
|
|
$c = \SystemClass::bar(5, "hello");
|
2022-12-18 17:15:15 +01:00
|
|
|
echo \SystemClass::HELLO;',
|
2019-03-25 05:07:32 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-02-27 21:20:24 +01:00
|
|
|
/**
|
2020-08-26 16:41:47 +02:00
|
|
|
* @psalm-pure
|
2020-02-27 21:20:24 +01:00
|
|
|
*/
|
|
|
|
private function getOperatingSystemStyledPath(string $file): string
|
|
|
|
{
|
|
|
|
return implode(DIRECTORY_SEPARATOR, explode('/', $file));
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testLoadStubFileWithRelativePath(): void
|
2020-02-26 22:47:20 +01:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2020-02-26 22:47:20 +01:00
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="./tests/../tests/fixtures/stubs/systemclass.phpstub" />
|
2020-02-26 22:47:20 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-02-26 22:47:20 +01:00
|
|
|
);
|
|
|
|
|
2021-02-14 00:42:34 +01:00
|
|
|
$path = $this->getOperatingSystemStyledPath('tests/fixtures/stubs/systemclass.phpstub');
|
2020-06-21 17:43:08 +02:00
|
|
|
$stub_files = $this->project_analyzer->getConfig()->getStubFiles();
|
2021-12-03 21:07:25 +01:00
|
|
|
$this->assertStringContainsString($path, reset($stub_files));
|
2020-02-26 22:47:20 +01:00
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testLoadStubFileWithAbsolutePath(): void
|
2020-02-26 22:47:20 +01:00
|
|
|
{
|
|
|
|
$runDir = dirname(__DIR__);
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
$runDir,
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2020-02-26 22:47:20 +01:00
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="' . $runDir . '/tests/fixtures/stubs/systemclass.phpstub" />
|
2020-02-26 22:47:20 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-02-26 22:47:20 +01:00
|
|
|
);
|
|
|
|
|
2021-02-14 00:42:34 +01:00
|
|
|
$path = $this->getOperatingSystemStyledPath('tests/fixtures/stubs/systemclass.phpstub');
|
2020-06-21 17:43:08 +02:00
|
|
|
$stub_files = $this->project_analyzer->getConfig()->getStubFiles();
|
2021-12-03 21:07:25 +01:00
|
|
|
$this->assertStringContainsString($path, reset($stub_files));
|
2020-02-26 22:47:20 +01:00
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileConstant(): void
|
2019-03-25 05:07:32 +01:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2019-03-25 05:07:32 +01:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/systemclass.phpstub" />
|
2019-03-25 05:07:32 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2019-03-25 05:07:32 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace A\B\C;
|
|
|
|
|
|
|
|
$d = ROOT_CONST_CONSTANT;
|
|
|
|
$e = \ROOT_CONST_CONSTANT;
|
|
|
|
$f = ROOT_DEFINE_CONSTANT;
|
2022-12-18 17:15:15 +01:00
|
|
|
$g = \ROOT_DEFINE_CONSTANT;',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
2021-12-09 16:22:35 +01:00
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testStubFileParentClass(): void
|
|
|
|
{
|
|
|
|
$this->expectException(CodeException::class);
|
|
|
|
$this->expectExceptionMessage('ImplementedParamTypeMismatch');
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
|
|
|
<file name="tests/fixtures/stubs/systemclass.phpstub" />
|
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2021-12-09 16:22:35 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace A\B\C;
|
|
|
|
|
|
|
|
class Foo extends \SystemClass
|
|
|
|
{
|
|
|
|
public function foo(string $a, string $b): string
|
|
|
|
{
|
|
|
|
return $a . $b;
|
|
|
|
}
|
|
|
|
}
|
2022-12-18 17:15:15 +01:00
|
|
|
',
|
2021-12-09 16:22:35 +01:00
|
|
|
);
|
|
|
|
|
2021-12-09 20:40:40 +01:00
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testStubFileCircularReference(): void
|
|
|
|
{
|
|
|
|
$this->expectException(CodeException::class);
|
|
|
|
$this->expectExceptionMessage('CircularReference');
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
|
|
|
<file name="tests/fixtures/stubs/CircularReference.phpstub" />
|
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2021-12-09 20:40:40 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2021-12-15 00:07:49 +01:00
|
|
|
class Foo extends Baz {}
|
2022-12-18 17:15:15 +01:00
|
|
|
',
|
2021-12-09 20:40:40 +01:00
|
|
|
);
|
|
|
|
|
2018-06-30 21:29:37 +02:00
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testPhpStormMetaParsingFile(): void
|
2019-02-16 17:16:52 +01:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2019-02-16 17:16:52 +01:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2019-02-17 00:50:25 +01:00
|
|
|
|
|
|
|
<stubs>
|
2019-05-10 00:23:14 +02:00
|
|
|
<file name="tests/fixtures/stubs/phpstorm.meta.php" />
|
2019-02-17 00:50:25 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2019-02-16 17:16:52 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace Ns {
|
|
|
|
class MyClass {
|
2023-01-24 11:24:52 +01:00
|
|
|
|
|
|
|
public const OBJECT = "object";
|
2023-01-24 12:31:58 +01:00
|
|
|
private const EXCEPTION = "exception";
|
2023-01-24 11:24:52 +01:00
|
|
|
|
2019-02-16 17:16:52 +01:00
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
public function create(string $s) {}
|
|
|
|
|
2022-11-27 10:19:05 +01:00
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
public function create2(string $s) {}
|
2023-01-24 11:24:52 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
public function create3(string $s) {}
|
2022-11-27 10:19:05 +01:00
|
|
|
|
2019-02-16 17:16:52 +01:00
|
|
|
/**
|
|
|
|
* @param mixed $s
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
public function foo($s) {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
public function bar(array $a) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
namespace {
|
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
function create(string $s) {}
|
|
|
|
|
2022-11-27 10:19:05 +01:00
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
function create2(string $s) {}
|
|
|
|
|
2019-02-16 17:16:52 +01:00
|
|
|
/**
|
|
|
|
* @param mixed $s
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
function foo($s) {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return mixed
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
function bar(array $a) {}
|
|
|
|
|
2020-03-01 23:11:44 +01:00
|
|
|
$a1 = (new \Ns\MyClass)->creAte("object");
|
|
|
|
$a2 = (new \Ns\MyClass)->creaTe("exception");
|
2019-02-16 17:16:52 +01:00
|
|
|
|
2022-11-27 10:19:05 +01:00
|
|
|
$y1 = (new \Ns\MyClass)->creAte2("object");
|
|
|
|
$y2 = (new \Ns\MyClass)->creaTe2("exception");
|
2023-01-24 11:24:52 +01:00
|
|
|
|
|
|
|
$const1 = (new \Ns\MyClass)->creAte3(\Ns\MyClass::OBJECT);
|
|
|
|
$const2 = (new \Ns\MyClass)->creaTe3("exception");
|
2022-11-27 10:19:05 +01:00
|
|
|
|
2020-03-01 23:11:44 +01:00
|
|
|
$b1 = \Create("object");
|
|
|
|
$b2 = \cReate("exception");
|
2019-02-16 17:16:52 +01:00
|
|
|
|
2020-03-01 23:11:44 +01:00
|
|
|
$e2 = \creAte(\LogicException::class);
|
2019-02-16 18:16:34 +01:00
|
|
|
|
2022-11-27 10:19:05 +01:00
|
|
|
$z1 = \Create2("object");
|
|
|
|
$z2 = \cReate2("exception");
|
|
|
|
|
|
|
|
$x2 = \creAte2(\LogicException::class);
|
|
|
|
|
2019-02-16 17:16:52 +01:00
|
|
|
$c1 = (new \Ns\MyClass)->foo(5);
|
|
|
|
$c2 = (new \Ns\MyClass)->bar(["hello"]);
|
|
|
|
|
2020-03-01 23:11:44 +01:00
|
|
|
$d1 = \foO(5);
|
|
|
|
$d2 = \baR(["hello"]);
|
2022-12-18 17:15:15 +01:00
|
|
|
}',
|
2019-02-16 17:16:52 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$context = new Context();
|
|
|
|
$this->analyzeFile($file_path, $context);
|
2022-11-27 10:19:05 +01:00
|
|
|
|
|
|
|
$this->assertContextVars(
|
|
|
|
[
|
|
|
|
'$a1===' => 'stdClass',
|
|
|
|
'$a2===' => 'Exception',
|
|
|
|
|
|
|
|
'$y1===' => 'stdClass',
|
|
|
|
'$y2===' => 'Exception',
|
|
|
|
|
2023-01-24 11:24:52 +01:00
|
|
|
'$const1===' => 'stdClass',
|
|
|
|
'$const2===' => 'Exception',
|
|
|
|
|
2022-11-27 10:19:05 +01:00
|
|
|
'$b1===' => 'stdClass',
|
|
|
|
'$b2===' => 'Exception',
|
|
|
|
|
|
|
|
'$e2===' => 'LogicException',
|
|
|
|
|
|
|
|
'$z1===' => 'stdClass',
|
|
|
|
'$z2===' => 'Exception',
|
|
|
|
|
|
|
|
'$x2===' => 'LogicException',
|
|
|
|
|
|
|
|
'$c1===' => "5",
|
|
|
|
'$c2===' => "'hello'",
|
|
|
|
|
|
|
|
'$d1===' => "5",
|
2022-12-21 00:18:50 +01:00
|
|
|
'$d2===' => "'hello'",
|
2022-11-27 10:19:05 +01:00
|
|
|
],
|
2022-12-21 00:18:50 +01:00
|
|
|
$context,
|
2022-11-27 10:19:05 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @param array<string, string> $assertions */
|
|
|
|
private function assertContextVars(array $assertions, Context $context): void
|
|
|
|
{
|
|
|
|
$actual_vars = [];
|
|
|
|
foreach ($assertions as $var => $_) {
|
|
|
|
$exact = false;
|
|
|
|
|
|
|
|
if ($var && strpos($var, '===') === strlen($var) - 3) {
|
|
|
|
$var = substr($var, 0, -3);
|
|
|
|
$exact = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($context->vars_in_scope[$var])) {
|
|
|
|
$value = $context->vars_in_scope[$var]->getId($exact);
|
|
|
|
if ($exact) {
|
|
|
|
$actual_vars[$var . '==='] = $value;
|
|
|
|
} else {
|
|
|
|
$actual_vars[$var] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->assertSame($assertions, $actual_vars);
|
2019-02-16 17:16:52 +01:00
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testNamespacedStubClass(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/namespaced_class.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
$a = new Foo\SystemClass();
|
|
|
|
echo Foo\SystemClass::HELLO;
|
|
|
|
|
|
|
|
$b = $a->foo(5, "hello");
|
2018-08-08 22:13:37 +02:00
|
|
|
$c = Foo\SystemClass::bar(5, "hello");
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
echo Foo\BAR;',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubRegularFunction(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/custom_functions.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
echo barBar("hello");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubVariadicFunction(): void
|
2018-12-01 01:21:14 +01:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-12-01 01:21:14 +01:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/custom_functions.phpstub" />
|
2018-12-01 01:21:14 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-12-01 01:21:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
variadic("bat", "bam");',
|
2018-12-01 01:21:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubVariadicFunctionWrongArgType(): void
|
2018-12-01 01:21:14 +01:00
|
|
|
{
|
2019-05-17 00:36:36 +02:00
|
|
|
$this->expectExceptionMessage('InvalidScalarArgument');
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(CodeException::class);
|
2018-12-01 01:21:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-12-01 01:21:14 +01:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/custom_functions.phpstub" />
|
2018-12-01 01:21:14 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-12-01 01:21:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
variadic("bat", 5);',
|
2018-12-01 01:21:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testUserVariadicWithFalseVariadic(): void
|
2018-12-01 01:21:14 +01:00
|
|
|
{
|
2019-05-17 00:36:36 +02:00
|
|
|
$this->expectExceptionMessage('TooManyArguments');
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(CodeException::class);
|
2018-12-01 01:21:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-12-01 01:21:14 +01:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-12-01 01:21:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @param string ...$bar
|
|
|
|
*/
|
|
|
|
function variadic() : void {}
|
2022-12-18 17:15:15 +01:00
|
|
|
variadic("hello");',
|
2018-12-01 01:21:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2018-06-30 21:29:37 +02:00
|
|
|
/**
|
2020-08-23 16:32:07 +02:00
|
|
|
* @runInSeparateProcess
|
2018-06-30 21:29:37 +02:00
|
|
|
*/
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testPolyfilledFunction(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
2020-08-13 15:14:27 +02:00
|
|
|
errorLevel="1"
|
2021-02-14 00:42:34 +01:00
|
|
|
autoloader="tests/fixtures/stubs/polyfill.phpstub"
|
2018-06-30 21:29:37 +02:00
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2018-07-03 17:17:52 +02:00
|
|
|
$a = random_bytes(16);
|
2022-12-18 17:15:15 +01:00
|
|
|
$b = new_random_bytes(16);',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-08-13 15:14:27 +02:00
|
|
|
/**
|
2020-08-23 16:32:07 +02:00
|
|
|
* @runInSeparateProcess
|
2020-08-13 15:14:27 +02:00
|
|
|
*/
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testConditionalConstantDefined(): void
|
2020-08-13 15:14:27 +02:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
2021-02-14 00:42:34 +01:00
|
|
|
autoloader="tests/fixtures/stubs/conditional_constant_define_inferred.phpstub"
|
2020-08-13 15:14:27 +02:00
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-08-13 15:14:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2020-11-08 21:36:30 +01:00
|
|
|
/** @psalm-suppress MixedArgument */
|
2022-12-18 17:15:15 +01:00
|
|
|
echo CODE_DIR;',
|
2020-08-13 15:14:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2023-07-03 22:28:25 +02:00
|
|
|
/**
|
|
|
|
* @runInSeparateProcess
|
|
|
|
*/
|
|
|
|
public function testStubbedConstantVarCommentType(): void
|
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
|
|
|
<file name="tests/fixtures/stubs/constant_var_comment.phpstub" />
|
|
|
|
</stubs>
|
|
|
|
</psalm>',
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @param non-empty-string $arg
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
function hello($arg) {
|
|
|
|
echo $arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
hello(FOO_BAR);',
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2018-11-29 06:05:56 +01:00
|
|
|
/**
|
2020-08-23 16:32:07 +02:00
|
|
|
* @runInSeparateProcess
|
2018-11-29 06:05:56 +01:00
|
|
|
*/
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testClassAlias(): void
|
2018-11-29 06:05:56 +01:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
2020-08-13 15:14:27 +02:00
|
|
|
errorLevel="1"
|
2021-02-14 00:42:34 +01:00
|
|
|
autoloader="tests/fixtures/stubs/class_alias.phpstub"
|
2018-11-29 06:05:56 +01:00
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-11-29 06:05:56 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2018-12-21 07:21:00 +01:00
|
|
|
namespace ClassAliasStubTest;
|
|
|
|
|
2018-11-29 06:05:56 +01:00
|
|
|
function foo(A $a) : void {}
|
|
|
|
|
|
|
|
foo(new B());
|
2018-11-29 06:46:34 +01:00
|
|
|
foo(new C());
|
2018-11-29 06:05:56 +01:00
|
|
|
|
|
|
|
function bar(B $b) : void {}
|
|
|
|
|
|
|
|
bar(new A());
|
|
|
|
|
|
|
|
$a = new B();
|
|
|
|
|
|
|
|
echo $a->foo;
|
|
|
|
|
2018-12-05 16:36:42 +01:00
|
|
|
echo $a->bar("hello");
|
|
|
|
|
|
|
|
function f(): A {
|
|
|
|
return new A;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getAliased(): B {
|
|
|
|
return f();
|
2018-12-21 07:21:00 +01:00
|
|
|
}
|
|
|
|
|
2018-12-21 15:29:23 +01:00
|
|
|
$d = new D();
|
|
|
|
|
2018-12-21 17:39:28 +01:00
|
|
|
D::bat();
|
|
|
|
$d::bat();
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
class E implements IAlias {}',
|
2018-11-29 06:05:56 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFunctionWithFunctionExists(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/custom_functions.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
function_exists("fooBar");
|
2022-12-18 17:15:15 +01:00
|
|
|
echo barBar("hello");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testNamespacedStubFunctionWithFunctionExists(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/custom_functions.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace A;
|
|
|
|
function_exists("fooBar");
|
2022-12-18 17:15:15 +01:00
|
|
|
echo barBar("hello");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testNoStubFunction(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2019-05-17 00:36:36 +02:00
|
|
|
$this->expectExceptionMessage('UndefinedFunction - /src/somefile.php:2:22 - Function barBar does not exist');
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(CodeException::class);
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
echo barBar("hello");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testNamespacedStubFunction(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/namespaced_functions.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
echo Foo\barBar("hello");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testConditionalNamespacedStubFunction(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/conditional_namespaced_functions.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
echo Foo\barBar("hello");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testConditionallyExtendingInterface(): void
|
2019-06-10 05:50:18 +02:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2019-06-10 05:50:18 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/conditional_interface.phpstub" />
|
2019-06-10 05:50:18 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2019-06-10 05:50:18 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
class C implements I1, I2, I3, I4 {}
|
|
|
|
|
|
|
|
function foo(I5 $d) : void {
|
|
|
|
$d->getMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
function bar(I6 $d) : void {
|
|
|
|
$d->getMessage();
|
2019-06-28 16:17:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function bat(I7 $d) : void {
|
|
|
|
$d->getMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
function baz(I8 $d) : void {
|
|
|
|
$d->getMessage();
|
2022-12-18 17:15:15 +01:00
|
|
|
}',
|
2019-06-10 05:50:18 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileWithExistingClassDefinition(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/DomainException.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
2022-12-18 17:15:15 +01:00
|
|
|
$a = new DomainException(5);',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2022-11-12 02:14:21 +01:00
|
|
|
/** @return iterable<string, array{string,string}> */
|
2021-03-06 23:18:51 +01:00
|
|
|
public function versionDependentStubsProvider(): iterable
|
|
|
|
{
|
|
|
|
yield '7.0' => [
|
|
|
|
'7.0',
|
|
|
|
'<?php
|
|
|
|
$a = new SomeClass;
|
2022-12-18 17:15:15 +01:00
|
|
|
$a->something("zzz");',
|
2021-03-06 23:18:51 +01:00
|
|
|
];
|
|
|
|
yield '8.0' => [
|
|
|
|
'8.0',
|
|
|
|
'<?php
|
|
|
|
$a = new SomeClass;
|
2022-12-18 17:15:15 +01:00
|
|
|
$a->something();',
|
2021-03-06 23:18:51 +01:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider versionDependentStubsProvider */
|
|
|
|
public function testVersionDependentStubs(string $php_version, string $code): void
|
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
|
|
|
<file name="tests/fixtures/stubs/VersionDependentMethods.phpstub" />
|
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2021-03-06 23:18:51 +01:00
|
|
|
);
|
2021-11-27 01:06:33 +01:00
|
|
|
$this->project_analyzer->setPhpVersion($php_version, 'tests');
|
2021-03-06 23:18:51 +01:00
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile($file_path, $code);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileWithPartialClassDefinitionWithMoreMethods(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/partial_class.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class PartiallyStubbedClass {
|
|
|
|
/**
|
|
|
|
* @param string $a
|
|
|
|
* @return object
|
|
|
|
*/
|
|
|
|
public function foo(string $a) {
|
|
|
|
return new self;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function bar(int $i) : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class A {}
|
|
|
|
|
|
|
|
(new PartiallyStubbedClass())->foo(A::class);
|
2022-12-18 17:15:15 +01:00
|
|
|
(new PartiallyStubbedClass())->bar(5);',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testExtendOnlyStubbedClass(): void
|
2020-03-29 06:13:01 +02:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/partial_class.phpstub" />
|
2020-03-29 06:13:01 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-03-29 06:13:01 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A extends PartiallyStubbedClass {}
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
(new A)->foo(A::class);',
|
2020-03-29 06:13:01 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileWithExtendedStubbedClass(): void
|
2019-04-21 17:30:42 +02:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2019-04-21 17:30:42 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/partial_class.phpstub" />
|
2019-04-21 17:30:42 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2019-04-21 17:30:42 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class Bar extends PartiallyStubbedClass {}
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
new Bar();',
|
2019-04-21 17:30:42 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileWithPartialClassDefinitionWithCoercion(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2019-05-17 00:36:36 +02:00
|
|
|
$this->expectExceptionMessage('TypeCoercion');
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(CodeException::class);
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/partial_class.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class PartiallyStubbedClass {
|
|
|
|
/**
|
|
|
|
* @param string $a
|
|
|
|
* @return object
|
|
|
|
*/
|
|
|
|
public function foo(string $a) {
|
|
|
|
return new self;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
(new PartiallyStubbedClass())->foo("dasda");',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileWithPartialClassDefinitionGeneralReturnType(): void
|
2018-06-30 21:29:37 +02:00
|
|
|
{
|
2019-05-17 00:36:36 +02:00
|
|
|
$this->expectExceptionMessage('InvalidReturnStatement');
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(CodeException::class);
|
2018-11-11 18:01:14 +01:00
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
2018-06-30 21:29:37 +02:00
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2018-06-30 21:29:37 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/partial_class.phpstub" />
|
2018-06-30 21:29:37 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class PartiallyStubbedClass {
|
|
|
|
/**
|
|
|
|
* @param string $a
|
|
|
|
* @return object
|
|
|
|
*/
|
|
|
|
public function foo(string $a) {
|
|
|
|
return new \stdClass;
|
|
|
|
}
|
2022-12-18 17:15:15 +01:00
|
|
|
}',
|
2018-06-30 21:29:37 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
2019-07-11 18:51:43 +02:00
|
|
|
|
2020-09-12 17:24:05 +02:00
|
|
|
public function testStubFileWithTemplatedClassDefinitionAndMagicMethodOverride(): void
|
2019-07-11 18:51:43 +02:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
2020-03-01 23:11:44 +01:00
|
|
|
<psalm
|
|
|
|
errorLevel="1"
|
|
|
|
>
|
2019-07-11 18:51:43 +02:00
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/templated_class.phpstub" />
|
2019-07-11 18:51:43 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2019-07-11 18:51:43 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
/**
|
|
|
|
* @param int $id
|
|
|
|
* @param ?int $lockMode
|
|
|
|
* @param ?int $lockVersion
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2023-01-03 23:08:39 +01:00
|
|
|
public function find($id, $lockMode = null, $lockVersion = null) {
|
|
|
|
return null;
|
|
|
|
}
|
2019-07-11 18:51:43 +02:00
|
|
|
}
|
|
|
|
|
2022-01-26 18:46:02 +01:00
|
|
|
/**
|
|
|
|
* @psalm-suppress MissingTemplateParam
|
|
|
|
*/
|
2019-07-11 18:51:43 +02:00
|
|
|
class B extends A {}
|
|
|
|
|
|
|
|
class Obj {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @method ?Obj find(int $id, $lockMode = null, $lockVersion = null)
|
|
|
|
*/
|
2022-12-18 17:15:15 +01:00
|
|
|
class C extends B {}',
|
2019-07-11 18:51:43 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
2019-09-01 22:52:40 +02:00
|
|
|
|
2021-12-05 18:51:26 +01:00
|
|
|
public function testInheritedMethodUsedInStub(): void
|
2019-09-01 22:52:40 +02:00
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm
|
|
|
|
findUnusedCode="true"
|
|
|
|
>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2019-09-01 22:52:40 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->project_analyzer->getCodebase()->reportUnusedCode();
|
|
|
|
|
|
|
|
$vendor_file_path = getcwd() . '/vendor/vendor_class.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$vendor_file_path,
|
|
|
|
'<?php
|
|
|
|
namespace SomeVendor;
|
|
|
|
|
|
|
|
class VendorClass {
|
|
|
|
abstract public function foo() : void;
|
|
|
|
|
|
|
|
public static function vendorFunction(VendorClass $v) : void {
|
|
|
|
$v->foo();
|
|
|
|
}
|
2022-12-18 17:15:15 +01:00
|
|
|
}',
|
2019-09-01 22:52:40 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
class MyClass extends \SomeVendor\VendorClass {
|
|
|
|
public function foo() : void {}
|
|
|
|
}
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
\SomeVendor\VendorClass::vendorFunction(new MyClass);',
|
2019-09-01 22:52:40 +02:00
|
|
|
);
|
|
|
|
|
2020-03-28 21:30:56 +01:00
|
|
|
$this->analyzeFile($file_path, new Context(), false);
|
2019-09-01 22:52:40 +02:00
|
|
|
|
2019-12-02 21:24:01 +01:00
|
|
|
$this->project_analyzer->consolidateAnalyzedData();
|
2019-09-01 22:52:40 +02:00
|
|
|
}
|
2020-09-13 22:40:31 +02:00
|
|
|
|
|
|
|
public function testStubOverridingMissingClass(): void
|
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/MissingClass.phpstub" />
|
2020-09-13 22:40:31 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-09-13 22:40:31 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
2020-09-14 04:39:03 +02:00
|
|
|
'<?php
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
echo "hello";',
|
2020-09-13 22:40:31 +02:00
|
|
|
);
|
|
|
|
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(InvalidClasslikeOverrideException::class);
|
2020-09-13 22:40:31 +02:00
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testStubOverridingMissingMethod(): void
|
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/MissingMethod.phpstub" />
|
2020-09-13 22:40:31 +02:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-09-13 22:40:31 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
2020-09-14 04:39:03 +02:00
|
|
|
'<?php
|
|
|
|
|
2022-12-18 17:15:15 +01:00
|
|
|
echo "hello";',
|
2020-09-13 22:40:31 +02:00
|
|
|
);
|
|
|
|
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(InvalidMethodOverrideException::class);
|
2020-09-13 22:40:31 +02:00
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
2020-12-01 16:26:45 +01:00
|
|
|
|
|
|
|
public function testStubReplacingInterfaceDocblock(): void
|
|
|
|
{
|
|
|
|
$this->project_analyzer = $this->getProjectAnalyzerWithConfig(
|
|
|
|
TestConfig::loadFromXML(
|
|
|
|
dirname(__DIR__),
|
|
|
|
'<?xml version="1.0"?>
|
|
|
|
<psalm>
|
|
|
|
<projectFiles>
|
|
|
|
<directory name="src" />
|
|
|
|
</projectFiles>
|
|
|
|
<stubs>
|
2021-02-14 00:42:34 +01:00
|
|
|
<file name="tests/fixtures/stubs/Doctrine.phpstub" />
|
2020-12-01 16:26:45 +01:00
|
|
|
</stubs>
|
2022-12-18 17:15:15 +01:00
|
|
|
</psalm>',
|
|
|
|
),
|
2020-12-01 16:26:45 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
getcwd() . '/vendor/doctrine/import.php',
|
|
|
|
'<?php
|
|
|
|
namespace Doctrine\ORM;
|
|
|
|
|
|
|
|
interface EntityManagerInterface
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @param string $entityName The name of the entity type.
|
|
|
|
* @param mixed $id The entity identifier.
|
|
|
|
*
|
|
|
|
* @return object|null The entity reference.
|
|
|
|
*/
|
|
|
|
public function getReference($entityName, $id);
|
|
|
|
}
|
|
|
|
|
|
|
|
class EntityManager implements EntityManagerInterface
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @psalm-suppress InvalidReturnType
|
|
|
|
*/
|
|
|
|
public function getReference($entityName, $id) {
|
|
|
|
/**
|
|
|
|
* @psalm-suppress InvalidReturnStatement
|
|
|
|
*/
|
|
|
|
return new \stdClass;
|
|
|
|
}
|
2022-12-18 17:15:15 +01:00
|
|
|
}',
|
2020-12-01 16:26:45 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$file_path = getcwd() . '/src/somefile.php';
|
|
|
|
|
|
|
|
$this->addFile(
|
|
|
|
$file_path,
|
|
|
|
'<?php
|
|
|
|
use Doctrine\ORM\EntityManager;
|
|
|
|
|
2021-07-17 00:38:39 +02:00
|
|
|
class A {}
|
2020-12-01 16:26:45 +01:00
|
|
|
|
|
|
|
function em(EntityManager $em) : void {
|
2021-07-17 00:38:39 +02:00
|
|
|
echo $em->getReference(A::class, 1);
|
2022-12-18 17:15:15 +01:00
|
|
|
}',
|
2020-12-01 16:26:45 +01:00
|
|
|
);
|
|
|
|
|
2021-12-03 20:29:06 +01:00
|
|
|
$this->expectException(CodeException::class);
|
2021-07-17 00:38:39 +02:00
|
|
|
$this->expectExceptionMessage('A|null');
|
2020-12-01 16:26:45 +01:00
|
|
|
|
|
|
|
$this->analyzeFile($file_path, new Context());
|
|
|
|
}
|
2018-06-30 21:29:37 +02:00
|
|
|
}
|