1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 12:24:49 +01:00

Ensure Stringable is always available to tests that need it

This commit is contained in:
Matt Brown 2020-10-29 19:41:10 -04:00 committed by Daniil Gentili
parent 7c1c2f77f7
commit fb81fa13f4
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
9 changed files with 103 additions and 23 deletions

View File

@ -96,6 +96,11 @@
<xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType> </xs:complexType>
<xs:complexType name="StubsAttributeType">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="preloadClasses" type="xs:boolean" default="false" />
</xs:complexType>
<xs:complexType name="IgnoreFilesType"> <xs:complexType name="IgnoreFilesType">
<xs:choice maxOccurs="unbounded"> <xs:choice maxOccurs="unbounded">
<xs:element name="directory" minOccurs="0" maxOccurs="unbounded" type="NameAttributeType" /> <xs:element name="directory" minOccurs="0" maxOccurs="unbounded" type="NameAttributeType" />
@ -144,7 +149,7 @@
<xs:complexType name="StubsType"> <xs:complexType name="StubsType">
<xs:sequence> <xs:sequence>
<xs:element name="file" maxOccurs="unbounded" type="NameAttributeType" /> <xs:element name="file" maxOccurs="unbounded" type="StubsAttributeType" />
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>

View File

@ -258,6 +258,11 @@ class Config
*/ */
private $mock_classes = []; private $mock_classes = [];
/**
* @var array<string, string>
*/
private $preloaded_stub_files = [];
/** /**
* @var array<string, string> * @var array<string, string>
*/ */
@ -1031,7 +1036,17 @@ class Config
); );
} }
$config->addStubFile($file_path); if (isset($stub_file['preloadClasses'])) {
$preload_classes = (string)$stub_file['preloadClasses'];
if ($preload_classes === 'true' || $preload_classes === '1') {
$config->addPreloadedStubFile($file_path);
} else {
$config->addStubFile($file_path);
}
} else {
$config->addStubFile($file_path);
}
} }
} }
@ -1700,6 +1715,56 @@ class Config
return $this->mock_classes; return $this->mock_classes;
} }
public function visitPreloadedStubFiles(Codebase $codebase, ?Progress $progress = null): void
{
if ($progress === null) {
$progress = new VoidProgress();
}
$core_generic_files = [];
if (\PHP_VERSION_ID < 80000 && $codebase->php_major_version >= 8) {
$stringable_path = dirname(__DIR__, 2) . '/stubs/Stringable.php';
if (!file_exists($stringable_path)) {
throw new \UnexpectedValueException('Cannot locate core generic classes');
}
$core_generic_files[] = $stringable_path;
}
$stub_files = array_merge($core_generic_files, $this->preloaded_stub_files);
if ($this->load_xdebug_stub) {
$xdebug_stub_path = dirname(__DIR__, 2) . '/stubs/Xdebug.php';
if (!file_exists($xdebug_stub_path)) {
throw new \UnexpectedValueException('Cannot locate XDebug stub');
}
$stub_files[] = $xdebug_stub_path;
}
if (!$stub_files) {
return;
}
foreach ($stub_files as $file_path) {
$file_path = \str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file_path);
$codebase->scanner->addFileToDeepScan($file_path);
}
$progress->debug('Registering preloaded stub files' . "\n");
$codebase->register_stub_files = true;
$codebase->scanFiles();
$codebase->register_stub_files = false;
$progress->debug('Finished registering preloaded stub files' . "\n");
}
public function visitStubFiles(Codebase $codebase, ?Progress $progress = null): void public function visitStubFiles(Codebase $codebase, ?Progress $progress = null): void
{ {
if ($progress === null) { if ($progress === null) {
@ -1741,16 +1806,6 @@ class Config
$core_generic_files[] = $ext_ds_path; $core_generic_files[] = $ext_ds_path;
} }
if (\version_compare(\PHP_VERSION, '8.0', '<') && $codebase->php_major_version >= 8) {
$stringable_path = dirname(__DIR__, 2) . '/stubs/Stringable.php';
if (!file_exists($stringable_path)) {
throw new \UnexpectedValueException('Cannot locate core generic classes');
}
$core_generic_files[] = $stringable_path;
}
$stub_files = array_merge($core_generic_files, $this->stub_files); $stub_files = array_merge($core_generic_files, $this->stub_files);
$phpstorm_meta_path = $this->base_dir . DIRECTORY_SEPARATOR . '.phpstorm.meta.php'; $phpstorm_meta_path = $this->base_dir . DIRECTORY_SEPARATOR . '.phpstorm.meta.php';
@ -1769,16 +1824,6 @@ class Config
} }
} }
if ($this->load_xdebug_stub) {
$xdebug_stub_path = dirname(__DIR__, 2) . '/stubs/Xdebug.php';
if (!file_exists($xdebug_stub_path)) {
throw new \UnexpectedValueException('Cannot locate XDebug stub');
}
$stub_files[] = $xdebug_stub_path;
}
foreach ($stub_files as $file_path) { foreach ($stub_files as $file_path) {
$file_path = \str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file_path); $file_path = \str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file_path);
$codebase->scanner->addFileToDeepScan($file_path); $codebase->scanner->addFileToDeepScan($file_path);
@ -2016,6 +2061,11 @@ class Config
return $this->stub_files; return $this->stub_files;
} }
public function addPreloadedStubFile(string $stub_file): void
{
$this->preloaded_stub_files[$stub_file] = $stub_file;
}
public function getPhpVersion(): ?string public function getPhpVersion(): ?string
{ {
if (isset($this->configured_php_version)) { if (isset($this->configured_php_version)) {

View File

@ -582,6 +582,8 @@ class ProjectAnalyzer
$this->config->initializePlugins($this); $this->config->initializePlugins($this);
$this->config->visitPreloadedStubFiles($this->codebase, $this->progress);
$this->codebase->scanFiles($this->threads); $this->codebase->scanFiles($this->threads);
$this->codebase->infer_types_from_usage = true; $this->codebase->infer_types_from_usage = true;
@ -604,6 +606,8 @@ class ProjectAnalyzer
$this->config->initializePlugins($this); $this->config->initializePlugins($this);
$this->config->visitPreloadedStubFiles($this->codebase, $this->progress);
$this->codebase->scanFiles($this->threads); $this->codebase->scanFiles($this->threads);
} else { } else {
$diff_no_files = true; $diff_no_files = true;
@ -987,6 +991,8 @@ class ProjectAnalyzer
$this->config->initializePlugins($this); $this->config->initializePlugins($this);
$this->config->visitPreloadedStubFiles($this->codebase, $this->progress);
$this->codebase->scanFiles($this->threads); $this->codebase->scanFiles($this->threads);
$this->config->visitStubFiles($this->codebase, $this->progress); $this->config->visitStubFiles($this->codebase, $this->progress);
@ -1120,6 +1126,8 @@ class ProjectAnalyzer
$this->config->initializePlugins($this); $this->config->initializePlugins($this);
$this->config->visitPreloadedStubFiles($this->codebase, $this->progress);
$this->codebase->scanFiles($this->threads); $this->codebase->scanFiles($this->threads);
$this->config->visitStubFiles($this->codebase, $this->progress); $this->config->visitStubFiles($this->codebase, $this->progress);
@ -1158,6 +1166,8 @@ class ProjectAnalyzer
$this->config->initializePlugins($this); $this->config->initializePlugins($this);
$this->config->visitPreloadedStubFiles($this->codebase, $this->progress);
$this->codebase->scanFiles($this->threads); $this->codebase->scanFiles($this->threads);
$this->config->visitStubFiles($this->codebase, $this->progress); $this->config->visitStubFiles($this->codebase, $this->progress);

View File

@ -245,7 +245,9 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements FileSour
$classlike_storage->class_implements['stringable'] = 'Stringable'; $classlike_storage->class_implements['stringable'] = 'Stringable';
} }
$this->codebase->scanner->queueClassLikeForScanning('Stringable'); if (\PHP_VERSION_ID >= 80000) {
$this->codebase->scanner->queueClassLikeForScanning('Stringable');
}
} }
if (!$this->scan_deep) { if (!$this->scan_deep) {

View File

@ -171,6 +171,9 @@ class DocumentationTest extends TestCase
$this->expectException(\Psalm\Exception\CodeException::class); $this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessageRegExp('/\b' . preg_quote($error_message, '/') . '\b/'); $this->expectExceptionMessageRegExp('/\b' . preg_quote($error_message, '/') . '\b/');
$codebase = $this->project_analyzer->getCodebase();
$codebase->config->visitPreloadedStubFiles($codebase);
$file_path = self::$src_dir_path . 'somefile.php'; $file_path = self::$src_dir_path . 'somefile.php';
$this->addFile($file_path, $code); $this->addFile($file_path, $code);

View File

@ -94,6 +94,7 @@ class TestCase extends BaseTestCase
public function analyzeFile($file_path, \Psalm\Context $context, bool $track_unused_suppressions = true): void public function analyzeFile($file_path, \Psalm\Context $context, bool $track_unused_suppressions = true): void
{ {
$codebase = $this->project_analyzer->getCodebase(); $codebase = $this->project_analyzer->getCodebase();
$codebase->addFilesToAnalyze([$file_path => $file_path]); $codebase->addFilesToAnalyze([$file_path => $file_path]);
$codebase->scanFiles(); $codebase->scanFiles();

View File

@ -391,6 +391,9 @@ class ToStringTest extends TestCase
], ],
'implicitStringableDisallowed' => [ 'implicitStringableDisallowed' => [
'<?php '<?php
interface Stringable {
function __toString() {}
}
function foo(Stringable $s): void {} function foo(Stringable $s): void {}
class Bar { class Bar {

View File

@ -84,6 +84,9 @@ trait InvalidCodeAnalysisTestTrait
$this->expectExceptionMessageRegExp('/\b' . preg_quote($error_message, '/') . '\b/'); $this->expectExceptionMessageRegExp('/\b' . preg_quote($error_message, '/') . '\b/');
} }
$codebase = $this->project_analyzer->getCodebase();
$codebase->config->visitPreloadedStubFiles($codebase);
$this->addFile($file_path, $code); $this->addFile($file_path, $code);
$this->analyzeFile($file_path, new Context()); $this->analyzeFile($file_path, new Context());
} }

View File

@ -76,6 +76,9 @@ trait ValidCodeAnalysisTestTrait
$this->project_analyzer->setPhpVersion($php_version); $this->project_analyzer->setPhpVersion($php_version);
$codebase = $this->project_analyzer->getCodebase();
$codebase->config->visitPreloadedStubFiles($codebase);
$file_path = self::$src_dir_path . 'somefile.php'; $file_path = self::$src_dir_path . 'somefile.php';
$this->addFile($file_path, $code); $this->addFile($file_path, $code);