From 62a0ece0357bb265c4f487a2bdea2c143dfb5dc9 Mon Sep 17 00:00:00 2001 From: Oliver Hader Date: Mon, 1 Nov 2021 18:04:42 +0100 Subject: [PATCH 1/2] !!! Allow plugins to modify Config::$fileExtensions early ProjectAnalyzer consumed Config::$fileExtensions early in its constructor - without having processed plugins' modifications, registering their custom scanners or analyzer implementations. This change * adds new specific interface \Psalm\Plugin\FileExtensionsInterface to be used by plugin implementations * extracts file extension handling from \Psalm\PluginRegistrationSocket and interface \Psalm\Plugin\RegistrationInterface to a new dedicated \Psalm\PluginFileExtensionsSocket and new interface \Psalm\Plugin\FileExtensionsInterface !!! this is a breaking change in PluginRegistrationSocket !!! * adds runtime in-memory cache for Config::$plugins * calls new method Config::processPluginFileExtensions(), providing modifications to file extension only early in ProjectAnalyzer * adjusts documentation --- UPGRADING.md | 11 ++ docs/running_psalm/checking_non_php_files.md | 13 +- .../plugins/authoring_plugins.md | 4 +- src/Psalm/Config.php | 132 +++++++++++------ .../Internal/Analyzer/ProjectAnalyzer.php | 1 + src/Psalm/Plugin/FileExtensionsInterface.php | 20 +++ .../Plugin/PluginEntryPointInterface.php | 2 +- .../Plugin/PluginFileExtensionsInterface.php | 12 ++ src/Psalm/Plugin/PluginInterface.php | 6 + src/Psalm/Plugin/RegistrationInterface.php | 17 --- src/Psalm/PluginFileExtensionsSocket.php | 136 ++++++++++++++++++ src/Psalm/PluginRegistrationSocket.php | 117 --------------- tests/Config/ConfigTest.php | 9 +- .../Plugin/FileTypeSelfRegisteringPlugin.php | 20 +-- 14 files changed, 304 insertions(+), 196 deletions(-) create mode 100644 src/Psalm/Plugin/FileExtensionsInterface.php create mode 100644 src/Psalm/Plugin/PluginFileExtensionsInterface.php create mode 100644 src/Psalm/Plugin/PluginInterface.php create mode 100644 src/Psalm/PluginFileExtensionsSocket.php diff --git a/UPGRADING.md b/UPGRADING.md index d25d8c8936d..915e8d9aebe 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -198,3 +198,14 @@ - [BC] Method `Psalm\DocComment::parse()` was removed - [BC] Class `Psalm\Type\Atomic\THtmlEscapedString` has been removed - [BC] Property `Psalm\Context::$vars_from_global` has been renamed to `$referenced_globals` + - [BC] Self-registration of file type scanners and file type analyzers has been changed + - `Psalm\Plugin\RegistrationInterface::addFileTypeScanner` was removed + - `Psalm\Plugin\RegistrationInterface::addFileTypeAnalyzer` was removed + - :information_source: migration possible using `Psalm\Plugin\FileExtensionsInterface` + - `Psalm\PluginRegistrationSocket::addFileTypeScanner` was removed + - `Psalm\PluginRegistrationSocket::getAdditionalFileTypeScanners` was removed + - `Psalm\PluginRegistrationSocket::addFileTypeAnalyzer` was removed + - `Psalm\PluginRegistrationSocket::getAdditionalFileTypeAnalyzers` was removed + - `Psalm\PluginRegistrationSocket::getAdditionalFileExtensions` was removed + - `Psalm\PluginRegistrationSocket::addFileExtension` was removed + - :information_source: migration possible using `Psalm\PluginFileExtensionsSocket` diff --git a/docs/running_psalm/checking_non_php_files.md b/docs/running_psalm/checking_non_php_files.md index dcadba5fb85..46a51c809c1 100644 --- a/docs/running_psalm/checking_non_php_files.md +++ b/docs/running_psalm/checking_non_php_files.md @@ -23,14 +23,21 @@ Plugins can register their own custom scanner and analyzer implementations for namespace Psalm\Example; use Psalm\Plugin\PluginEntryPointInterface; +use Psalm\Plugin\PluginFileExtensionsInterface; +use Psalm\Plugin\FileExtensionsInterface; use Psalm\Plugin\RegistrationInterface; -class CustomPlugin implements PluginEntryPointInterface +class CustomPlugin implements PluginEntryPointInterface, PluginFileExtensionsInterface { public function __invoke(RegistrationInterface $registration, ?\SimpleXMLElement $config = null): void { - $registration->addFileTypeScanner('phpt', TemplateScanner::class); - $registration->addFileTypeAnalyzer('phpt', TemplateAnalyzer::class); + // ... regular plugin processes, stub registration, hook registration } + + public function processFileExtensions(FileExtensionsInterface $fileExtensions, ?SimpleXMLElement $config = null): void + { + $fileExtensions->addFileTypeScanner('phpt', TemplateScanner::class); + $fileExtensions->addFileTypeAnalyzer('phpt', TemplateAnalyzer::class); + } } ``` diff --git a/docs/running_psalm/plugins/authoring_plugins.md b/docs/running_psalm/plugins/authoring_plugins.md index 9690a1b4b5e..d08197c4b7b 100644 --- a/docs/running_psalm/plugins/authoring_plugins.md +++ b/docs/running_psalm/plugins/authoring_plugins.md @@ -39,8 +39,8 @@ To register a stub file manually use `Psalm\Plugin\RegistrationInterface::addStu In addition to XML configuration node `` plugins can register their own custom scanner and analyzer implementations for particular file extensions, e.g. -* `Psalm\Plugin\RegistrationInterface::addFileTypeScanner('html', CustomFileScanner::class)` -* `Psalm\Plugin\RegistrationInterface::addFileTypeAnalyzer('html', CustomFileAnalyzer::class)` +* `Psalm\Plugin\FileExtensionsInterface::addFileTypeScanner('html', CustomFileScanner::class)` +* `Psalm\Plugin\FileExtensionsInterface::addFileTypeAnalyzer('html', CustomFileAnalyzer::class)` ## Publishing your plugin on Packagist diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index 56982c5fc52..a5c876b66a6 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -36,6 +36,8 @@ use Psalm\Issue\PropertyIssue; use Psalm\Issue\VariableIssue; use Psalm\Plugin\PluginEntryPointInterface; +use Psalm\Plugin\PluginFileExtensionsInterface; +use Psalm\Plugin\PluginInterface; use Psalm\Progress\Progress; use Psalm\Progress\VoidProgress; use SimpleXMLElement; @@ -593,6 +595,11 @@ class Config "xdebug" => false, ]; + /** + * @var array + */ + private $plugins = []; + protected function __construct() { self::$instance = $this; @@ -1372,6 +1379,40 @@ public function getPluginClasses(): array return $this->plugin_classes; } + public function processPluginFileExtensions(ProjectAnalyzer $projectAnalyzer): void + { + $projectAnalyzer->progress->debug('Process plugin adjustments...' . PHP_EOL); + $socket = new PluginFileExtensionsSocket($this); + foreach ($this->plugin_classes as $pluginClassEntry) { + $pluginClassName = $pluginClassEntry['class']; + $pluginConfig = $pluginClassEntry['config']; + $plugin = $this->loadPlugin($projectAnalyzer, $pluginClassName); + if (!$plugin instanceof PluginFileExtensionsInterface) { + continue; + } + try { + $plugin->processFileExtensions($socket, $pluginConfig); + } catch (Throwable $t) { + throw new ConfigException( + 'Failed to process plugin file extensions ' . $pluginClassName, + 1635800581, + $t + ); + } + $projectAnalyzer->progress->debug('Initialized plugin ' . $pluginClassName . ' successfully' . PHP_EOL); + } + // populate additional aspects after plugins have been initialized + foreach ($socket->getAdditionalFileExtensions() as $fileExtension) { + $this->file_extensions[] = $fileExtension; + } + foreach ($socket->getAdditionalFileTypeScanners() as $extension => $className) { + $this->filetype_scanners[$extension] = $className; + } + foreach ($socket->getAdditionalFileTypeAnalyzers() as $extension => $className) { + $this->filetype_analyzers[$extension] = $className; + } + } + /** * Initialises all the plugins (done once the config is fully loaded) */ @@ -1387,38 +1428,22 @@ public function initializePlugins(ProjectAnalyzer $project_analyzer): void $plugin_class_name = $plugin_class_entry['class']; $plugin_config = $plugin_class_entry['config']; - try { - // Below will attempt to load plugins from the project directory first. - // Failing that, it will use registered autoload chain, which will load - // plugins from Psalm directory or phar file. If that fails as well, it - // will fall back to project autoloader. It may seem that the last step - // will always fail, but it's only true if project uses Composer autoloader - if ($this->composer_class_loader - && ($plugin_class_path = $this->composer_class_loader->findFile($plugin_class_name)) - ) { - $project_analyzer->progress->debug( - 'Loading plugin ' . $plugin_class_name . ' via require' . PHP_EOL - ); - - self::requirePath($plugin_class_path); - } else { - if (!class_exists($plugin_class_name)) { - throw new UnexpectedValueException($plugin_class_name . ' is not a known class'); - } - } + $plugin = $this->loadPlugin($project_analyzer, $plugin_class_name); + if (!$plugin instanceof PluginEntryPointInterface) { + continue; + } - /** - * @psalm-suppress InvalidStringClass - * - * @var PluginEntryPointInterface - */ - $plugin_object = new $plugin_class_name; - $plugin_object($socket, $plugin_config); - } catch (Throwable $e) { - throw new ConfigException('Failed to load plugin ' . $plugin_class_name, 0, $e); + try { + $plugin($socket, $plugin_config); + } catch (Throwable $t) { + throw new ConfigException( + 'Failed to invoke plugin ' . $plugin_class_name, + 1635800582, + $t + ); } - $project_analyzer->progress->debug('Loaded plugin ' . $plugin_class_name . ' successfully' . PHP_EOL); + $project_analyzer->progress->debug('Initialized plugin ' . $plugin_class_name . ' successfully' . PHP_EOL); } foreach ($this->filetype_scanner_paths as $extension => $path) { @@ -1447,28 +1472,53 @@ public function initializePlugins(ProjectAnalyzer $project_analyzer): void foreach ($this->plugin_paths as $path) { try { - $plugin_object = new FileBasedPluginAdapter($path, $this, $codebase); - $plugin_object($socket); + $plugin = new FileBasedPluginAdapter($path, $this, $codebase); + $plugin($socket); } catch (Throwable $e) { throw new ConfigException('Failed to load plugin ' . $path, 0, $e); } } - // populate additional aspects after plugins have been initialized - foreach ($socket->getAdditionalFileExtensions() as $fileExtension) { - $this->file_extensions[] = $fileExtension; - } - foreach ($socket->getAdditionalFileTypeScanners() as $extension => $className) { - $this->filetype_scanners[$extension] = $className; - } - foreach ($socket->getAdditionalFileTypeAnalyzers() as $extension => $className) { - $this->filetype_analyzers[$extension] = $className; - } new HtmlFunctionTainter(); $socket->registerHooksFromClass(HtmlFunctionTainter::class); } + private function loadPlugin(ProjectAnalyzer $projectAnalyzer, string $pluginClassName): PluginInterface + { + if (isset($this->plugins[$pluginClassName])) { + return $this->plugins[$pluginClassName]; + } + try { + // Below will attempt to load plugins from the project directory first. + // Failing that, it will use registered autoload chain, which will load + // plugins from Psalm directory or phar file. If that fails as well, it + // will fall back to project autoloader. It may seem that the last step + // will always fail, but it's only true if project uses Composer autoloader + if ($this->composer_class_loader + && ($pluginclas_class_path = $this->composer_class_loader->findFile($pluginClassName)) + ) { + $projectAnalyzer->progress->debug( + 'Loading plugin ' . $pluginClassName . ' via require' . PHP_EOL + ); + + self::requirePath($pluginclas_class_path); + } else { + if (!class_exists($pluginClassName)) { + throw new \UnexpectedValueException($pluginClassName . ' is not a known class'); + } + } + if (!is_a($pluginClassName, PluginInterface::class, true)) { + throw new \UnexpectedValueException($pluginClassName . ' is not a PluginInterface implementation'); + } + $this->plugins[$pluginClassName] = new $pluginClassName; + $projectAnalyzer->progress->debug('Loaded plugin ' . $pluginClassName . PHP_EOL); + return $this->plugins[$pluginClassName]; + } catch (Throwable $e) { + throw new ConfigException('Failed to load plugin ' . $pluginClassName, 0, $e); + } + } + private static function requirePath(string $path): void { /** @psalm-suppress UnresolvableInclude */ diff --git a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index fe3b80318df..8904b472c30 100644 --- a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -306,6 +306,7 @@ public function __construct( $this->stdout_report_options = $stdout_report_options; $this->generated_report_options = $generated_report_options; + $this->config->processPluginFileExtensions($this); $file_extensions = $this->config->getFileExtensions(); foreach ($this->config->getProjectDirectories() as $dir_name) { diff --git a/src/Psalm/Plugin/FileExtensionsInterface.php b/src/Psalm/Plugin/FileExtensionsInterface.php new file mode 100644 index 00000000000..2f762cc5a91 --- /dev/null +++ b/src/Psalm/Plugin/FileExtensionsInterface.php @@ -0,0 +1,20 @@ + $className + */ + public function addFileTypeScanner(string $fileExtension, string $className): void; + + /** + * @param string $fileExtension e.g. `'html'` + * @param class-string $className + */ + public function addFileTypeAnalyzer(string $fileExtension, string $className): void; +} diff --git a/src/Psalm/Plugin/PluginEntryPointInterface.php b/src/Psalm/Plugin/PluginEntryPointInterface.php index f3377d68d8a..1ff713b47ae 100644 --- a/src/Psalm/Plugin/PluginEntryPointInterface.php +++ b/src/Psalm/Plugin/PluginEntryPointInterface.php @@ -4,7 +4,7 @@ use SimpleXMLElement; -interface PluginEntryPointInterface +interface PluginEntryPointInterface extends PluginInterface { public function __invoke(RegistrationInterface $registration, ?SimpleXMLElement $config = null): void; } diff --git a/src/Psalm/Plugin/PluginFileExtensionsInterface.php b/src/Psalm/Plugin/PluginFileExtensionsInterface.php new file mode 100644 index 00000000000..8f84c6fc65d --- /dev/null +++ b/src/Psalm/Plugin/PluginFileExtensionsInterface.php @@ -0,0 +1,12 @@ + $className - * @deprecated will be removed in v5.0, use \Psalm\Plugin\FileExtensionsInterface instead (#6788) - */ - public function addFileTypeScanner(string $fileExtension, string $className): void; - - /** - * @param string $fileExtension e.g. `'html'` - * @param class-string $className - * @deprecated will be removed in v5.0, use \Psalm\Plugin\FileExtensionsInterface instead (#6788) - */ - public function addFileTypeAnalyzer(string $fileExtension, string $className): void; } diff --git a/src/Psalm/PluginFileExtensionsSocket.php b/src/Psalm/PluginFileExtensionsSocket.php new file mode 100644 index 00000000000..3d669c2c495 --- /dev/null +++ b/src/Psalm/PluginFileExtensionsSocket.php @@ -0,0 +1,136 @@ +> + */ + private $additionalFileTypeScanners = []; + + /** + * @var array> + */ + private $additionalFileTypeAnalyzers = []; + + /** + * @var list + */ + private $additionalFileExtensions = []; + + /** + * @internal + */ + public function __construct(Config $config) + { + $this->config = $config; + } + + /** + * @param string $fileExtension e.g. `'html'` + * @param class-string $className + */ + public function addFileTypeScanner(string $fileExtension, string $className): void + { + if (!class_exists($className) || !is_a($className, FileScanner::class, true)) { + throw new LogicException( + sprintf( + 'Class %s must be of type %s', + $className, + FileScanner::class + ), + 1622727271 + ); + } + if (!empty($this->config->getFiletypeScanners()[$fileExtension]) + || !empty($this->additionalFileTypeScanners[$fileExtension]) + ) { + throw new LogicException( + sprintf('Cannot redeclare scanner for file-type %s', $fileExtension), + 1622727272 + ); + } + $this->additionalFileTypeScanners[$fileExtension] = $className; + $this->addFileExtension($fileExtension); + } + + /** + * @return array> + */ + public function getAdditionalFileTypeScanners(): array + { + return $this->additionalFileTypeScanners; + } + + /** + * @param string $fileExtension e.g. `'html'` + * @param class-string $className + */ + public function addFileTypeAnalyzer(string $fileExtension, string $className): void + { + if (!class_exists($className) || !is_a($className, FileAnalyzer::class, true)) { + throw new LogicException( + sprintf( + 'Class %s must be of type %s', + $className, + FileAnalyzer::class + ), + 1622727281 + ); + } + if (!empty($this->config->getFiletypeAnalyzers()[$fileExtension]) + || !empty($this->additionalFileTypeAnalyzers[$fileExtension]) + ) { + throw new LogicException( + sprintf('Cannot redeclare analyzer for file-type %s', $fileExtension), + 1622727282 + ); + } + $this->additionalFileTypeAnalyzers[$fileExtension] = $className; + $this->addFileExtension($fileExtension); + } + + /** + * @return array> + */ + public function getAdditionalFileTypeAnalyzers(): array + { + return $this->additionalFileTypeAnalyzers; + } + + /** + * @return list e.g. `['html', 'perl']` + */ + public function getAdditionalFileExtensions(): array + { + return $this->additionalFileExtensions; + } + + /** + * @param string $fileExtension e.g. `'html'` + */ + private function addFileExtension(string $fileExtension): void + { + /** @psalm-suppress RedundantCondition */ + if (!in_array($fileExtension, $this->additionalFileExtensions, true) + && !in_array($fileExtension, $this->config->getFileExtensions(), true) + ) { + $this->additionalFileExtensions[] = $fileExtension; + } + } +} diff --git a/src/Psalm/PluginRegistrationSocket.php b/src/Psalm/PluginRegistrationSocket.php index 7f2927adda5..c0829aff85d 100644 --- a/src/Psalm/PluginRegistrationSocket.php +++ b/src/Psalm/PluginRegistrationSocket.php @@ -3,9 +3,6 @@ namespace Psalm; use InvalidArgumentException; -use LogicException; -use Psalm\Internal\Analyzer\FileAnalyzer; -use Psalm\Internal\Scanner\FileScanner; use Psalm\Plugin\EventHandler\DynamicFunctionStorageProviderInterface; use Psalm\Plugin\EventHandler\FunctionExistenceProviderInterface; use Psalm\Plugin\EventHandler\FunctionParamsProviderInterface; @@ -20,10 +17,7 @@ use Psalm\Plugin\RegistrationInterface; use function class_exists; -use function in_array; -use function is_a; use function is_subclass_of; -use function sprintf; class PluginRegistrationSocket implements RegistrationInterface { @@ -33,21 +27,6 @@ class PluginRegistrationSocket implements RegistrationInterface /** @var Codebase */ private $codebase; - /** - * @var array> - */ - private $additionalFileTypeScanners = []; - - /** - * @var array> - */ - private $additionalFileTypeAnalyzers = []; - - /** - * @var list - */ - private $additionalFileExtensions = []; - /** * @internal */ @@ -114,100 +93,4 @@ public function registerHooksFromClass(string $handler): void $this->codebase->functions->dynamic_storage_provider->registerClass($handler); } } - - /** - * @param string $fileExtension e.g. `'html'` - * @param class-string $className - * @deprecated will be removed in v5.0, use \Psalm\Plugin\FileExtensionsInterface instead (#6788) - */ - public function addFileTypeScanner(string $fileExtension, string $className): void - { - if (!class_exists($className) || !is_a($className, FileScanner::class, true)) { - throw new LogicException( - sprintf( - 'Class %s must be of type %s', - $className, - FileScanner::class - ), - 1_622_727_271 - ); - } - if (!empty($this->config->getFiletypeScanners()[$fileExtension]) - || !empty($this->additionalFileTypeScanners[$fileExtension]) - ) { - throw new LogicException( - sprintf('Cannot redeclare scanner for file-type %s', $fileExtension), - 1_622_727_272 - ); - } - $this->additionalFileTypeScanners[$fileExtension] = $className; - $this->addFileExtension($fileExtension); - } - - /** - * @return array> - * @deprecated will be removed in v5.0, use \Psalm\PluginFileExtensionsSocket instead (#6788) - */ - public function getAdditionalFileTypeScanners(): array - { - return $this->additionalFileTypeScanners; - } - - /** - * @param string $fileExtension e.g. `'html'` - * @param class-string $className - * @deprecated will be removed in v5.0, use \Psalm\PluginFileExtensionsSocket instead (#6788) - */ - public function addFileTypeAnalyzer(string $fileExtension, string $className): void - { - if (!class_exists($className) || !is_a($className, FileAnalyzer::class, true)) { - throw new LogicException( - sprintf( - 'Class %s must be of type %s', - $className, - FileAnalyzer::class - ), - 1_622_727_281 - ); - } - if (!empty($this->config->getFiletypeAnalyzers()[$fileExtension]) - || !empty($this->additionalFileTypeAnalyzers[$fileExtension]) - ) { - throw new LogicException( - sprintf('Cannot redeclare analyzer for file-type %s', $fileExtension), - 1_622_727_282 - ); - } - $this->additionalFileTypeAnalyzers[$fileExtension] = $className; - $this->addFileExtension($fileExtension); - } - - /** - * @return array> - * @deprecated will be removed in v5.0, use \Psalm\PluginFileExtensionsSocket instead (#6788) - */ - public function getAdditionalFileTypeAnalyzers(): array - { - return $this->additionalFileTypeAnalyzers; - } - - /** - * @return list e.g. `['html', 'perl']` - * @deprecated will be removed in v5.0, use \Psalm\PluginFileExtensionsSocket instead (#6788) - */ - public function getAdditionalFileExtensions(): array - { - return $this->additionalFileExtensions; - } - - /** - * @param string $fileExtension e.g. `'html'` - * @deprecated will be removed in v5.0, use \Psalm\PluginFileExtensionsSocket instead (#6788) - */ - private function addFileExtension(string $fileExtension): void - { - if (!in_array($fileExtension, $this->config->getFileExtensions(), true)) { - $this->additionalFileExtensions[] = $fileExtension; - } - } } diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 9d5b5a97754..5711865a669 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -1416,7 +1416,7 @@ public function pluginRegistersScannerAndAnalyzer(int $flags, ?int $expectedExce $extension = uniqid('test'); $names = [ 'scanner' => uniqid('PsalmTestFileTypeScanner'), - 'analyzer' => uniqid('PsalmTestFileTypeAnaylzer'), + 'analyzer' => uniqid('PsalmTestFileTypeAnalyzer'), 'extension' => $extension, ]; $scannerMock = $this->getMockBuilder(FileScanner::class) @@ -1437,12 +1437,11 @@ public function pluginRegistersScannerAndAnalyzer(int $flags, ?int $expectedExce ', FileTypeSelfRegisteringPlugin::class ); - $projectAnalyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML(dirname(__DIR__, 2), $xml) - ); - try { + $projectAnalyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML(dirname(__DIR__, 2), $xml) + ); $config = $projectAnalyzer->getConfig(); $config->initializePlugins($projectAnalyzer); } catch (ConfigException $exception) { diff --git a/tests/Config/Plugin/FileTypeSelfRegisteringPlugin.php b/tests/Config/Plugin/FileTypeSelfRegisteringPlugin.php index e3e60e6948b..666e950e833 100644 --- a/tests/Config/Plugin/FileTypeSelfRegisteringPlugin.php +++ b/tests/Config/Plugin/FileTypeSelfRegisteringPlugin.php @@ -2,12 +2,12 @@ namespace Psalm\Tests\Config\Plugin; -use Psalm\Plugin\PluginEntryPointInterface; -use Psalm\Plugin\RegistrationInterface; +use Psalm\Plugin\FileExtensionsInterface; +use Psalm\Plugin\PluginFileExtensionsInterface; use SimpleXMLElement; use stdClass; -class FileTypeSelfRegisteringPlugin implements PluginEntryPointInterface +class FileTypeSelfRegisteringPlugin implements PluginFileExtensionsInterface { public const FLAG_SCANNER_TWICE = 1; public const FLAG_ANALYZER_TWICE = 2; @@ -25,32 +25,32 @@ class FileTypeSelfRegisteringPlugin implements PluginEntryPointInterface */ public static $flags = 0; - public function __invoke(RegistrationInterface $registration, ?SimpleXMLElement $config = null): void + public function processFileExtensions(FileExtensionsInterface $fileExtensions, ?SimpleXMLElement $config = null): void { if (self::$flags & self::FLAG_SCANNER_INVALID) { /** @psalm-suppress InvalidArgument */ - $registration->addFileTypeScanner(self::$names['extension'], stdClass::class); + $fileExtensions->addFileTypeScanner(self::$names['extension'], stdClass::class); } else { // that's the regular/valid case /** @psalm-suppress ArgumentTypeCoercion */ - $registration->addFileTypeScanner(self::$names['extension'], self::$names['scanner']); + $fileExtensions->addFileTypeScanner(self::$names['extension'], self::$names['scanner']); } if (self::$flags & self::FLAG_ANALYZER_INVALID) { /** @psalm-suppress InvalidArgument */ - $registration->addFileTypeAnalyzer(self::$names['extension'], stdClass::class); + $fileExtensions->addFileTypeAnalyzer(self::$names['extension'], stdClass::class); } else { // that's the regular/valid case /** @psalm-suppress ArgumentTypeCoercion */ - $registration->addFileTypeAnalyzer(self::$names['extension'], self::$names['analyzer']); + $fileExtensions->addFileTypeAnalyzer(self::$names['extension'], self::$names['analyzer']); } if (self::$flags & self::FLAG_SCANNER_TWICE) { /** @psalm-suppress ArgumentTypeCoercion */ - $registration->addFileTypeScanner(self::$names['extension'], self::$names['scanner']); + $fileExtensions->addFileTypeScanner(self::$names['extension'], self::$names['scanner']); } if (self::$flags & self::FLAG_ANALYZER_TWICE) { /** @psalm-suppress ArgumentTypeCoercion */ - $registration->addFileTypeAnalyzer(self::$names['extension'], self::$names['analyzer']); + $fileExtensions->addFileTypeAnalyzer(self::$names['extension'], self::$names['analyzer']); } } } From 3fedb5cce6c523bf667834497ca910a9b0ae1f36 Mon Sep 17 00:00:00 2001 From: Oliver Hader Date: Fri, 21 Jan 2022 15:53:06 +0100 Subject: [PATCH 2/2] Apply code styles --- src/Psalm/Config.php | 8 ++++---- src/Psalm/Plugin/FileExtensionsInterface.php | 1 + src/Psalm/Plugin/PluginFileExtensionsInterface.php | 1 + src/Psalm/Plugin/PluginInterface.php | 1 + src/Psalm/PluginFileExtensionsSocket.php | 9 +++++---- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index a5c876b66a6..d9fadf20fae 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -1395,7 +1395,7 @@ public function processPluginFileExtensions(ProjectAnalyzer $projectAnalyzer): v } catch (Throwable $t) { throw new ConfigException( 'Failed to process plugin file extensions ' . $pluginClassName, - 1635800581, + 1_635_800_581, $t ); } @@ -1438,7 +1438,7 @@ public function initializePlugins(ProjectAnalyzer $project_analyzer): void } catch (Throwable $t) { throw new ConfigException( 'Failed to invoke plugin ' . $plugin_class_name, - 1635800582, + 1_635_800_582, $t ); } @@ -1505,11 +1505,11 @@ private function loadPlugin(ProjectAnalyzer $projectAnalyzer, string $pluginClas self::requirePath($pluginclas_class_path); } else { if (!class_exists($pluginClassName)) { - throw new \UnexpectedValueException($pluginClassName . ' is not a known class'); + throw new UnexpectedValueException($pluginClassName . ' is not a known class'); } } if (!is_a($pluginClassName, PluginInterface::class, true)) { - throw new \UnexpectedValueException($pluginClassName . ' is not a PluginInterface implementation'); + throw new UnexpectedValueException($pluginClassName . ' is not a PluginInterface implementation'); } $this->plugins[$pluginClassName] = new $pluginClassName; $projectAnalyzer->progress->debug('Loaded plugin ' . $pluginClassName . PHP_EOL); diff --git a/src/Psalm/Plugin/FileExtensionsInterface.php b/src/Psalm/Plugin/FileExtensionsInterface.php index 2f762cc5a91..c23b3b98876 100644 --- a/src/Psalm/Plugin/FileExtensionsInterface.php +++ b/src/Psalm/Plugin/FileExtensionsInterface.php @@ -1,4 +1,5 @@ config->getFiletypeScanners()[$fileExtension]) @@ -62,7 +63,7 @@ public function addFileTypeScanner(string $fileExtension, string $className): vo ) { throw new LogicException( sprintf('Cannot redeclare scanner for file-type %s', $fileExtension), - 1622727272 + 1_622_727_272 ); } $this->additionalFileTypeScanners[$fileExtension] = $className; @@ -90,7 +91,7 @@ public function addFileTypeAnalyzer(string $fileExtension, string $className): v $className, FileAnalyzer::class ), - 1622727281 + 1_622_727_281 ); } if (!empty($this->config->getFiletypeAnalyzers()[$fileExtension]) @@ -98,7 +99,7 @@ public function addFileTypeAnalyzer(string $fileExtension, string $className): v ) { throw new LogicException( sprintf('Cannot redeclare analyzer for file-type %s', $fileExtension), - 1622727282 + 1_622_727_282 ); } $this->additionalFileTypeAnalyzers[$fileExtension] = $className;