mirror of
https://github.com/danog/psalm-plugin-laravel.git
synced 2024-11-26 20:34:48 +01:00
refactor: move app return type provider into container handler
This commit is contained in:
parent
29f88e6e9a
commit
d92e310bdd
@ -4,21 +4,83 @@ namespace Psalm\LaravelPlugin\Handlers\Application;
|
||||
|
||||
use Illuminate\Foundation\AliasLoader;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\Internal\MethodIdentifier;
|
||||
use Psalm\LaravelPlugin\Providers\ApplicationInterfaceProvider;
|
||||
use Psalm\LaravelPlugin\Providers\ApplicationProvider;
|
||||
use Psalm\LaravelPlugin\Util\ContainerResolver;
|
||||
use Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface;
|
||||
use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
|
||||
use Psalm\Plugin\Hook\FunctionReturnTypeProviderInterface;
|
||||
use Psalm\Plugin\Hook\MethodReturnTypeProviderInterface;
|
||||
use Psalm\StatementsSource;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
use Psalm\Type\Union;
|
||||
use function in_array;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* @see https://github.com/psalm/psalm-plugin-symfony/issues/25
|
||||
* psalm needs to know about any classes that could be returned before analysis begins. This is a naive first approach
|
||||
*/
|
||||
final class ContainerHandler implements AfterClassLikeVisitInterface
|
||||
final class ContainerHandler implements AfterClassLikeVisitInterface, FunctionReturnTypeProviderInterface, MethodReturnTypeProviderInterface
|
||||
{
|
||||
/**
|
||||
* @return array<array-key, lowercase-string>
|
||||
*/
|
||||
public static function getFunctionIds(): array
|
||||
{
|
||||
return ['app', 'resolve'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<\PhpParser\Node\Arg> $call_args
|
||||
*/
|
||||
public static function getFunctionReturnType(StatementsSource $statements_source, string $function_id, array $call_args, Context $context, CodeLocation $code_location): ?Union
|
||||
{
|
||||
if (!$call_args) {
|
||||
return new Union([
|
||||
new TNamedObject(get_class(ApplicationProvider::getApp())),
|
||||
]);
|
||||
}
|
||||
|
||||
return ContainerResolver::resolvePsalmTypeFromApplicationContainerViaArgs($statements_source->getNodeTypeProvider(), $call_args) ?? Type::getMixed();
|
||||
}
|
||||
|
||||
public static function getClassLikeNames(): array
|
||||
{
|
||||
return [get_class(ApplicationProvider::getApp())];
|
||||
}
|
||||
|
||||
public static function getMethodReturnType(
|
||||
StatementsSource $source,
|
||||
string $fq_classlike_name,
|
||||
string $method_name_lowercase,
|
||||
array $call_args,
|
||||
Context $context,
|
||||
CodeLocation $code_location,
|
||||
?array $template_type_parameters = null,
|
||||
?string $called_fq_classlike_name = null,
|
||||
?string $called_method_name_lowercase = null
|
||||
) : ?Type\Union {
|
||||
// lumen doesn't have the likes of makeWith, so we will ensure these methods actually exist on the underlying
|
||||
// app contract
|
||||
$methods = array_filter(['make', 'makewith'], function (string $methodName) use ($source, $fq_classlike_name) {
|
||||
$methodId = new MethodIdentifier($fq_classlike_name, $methodName);
|
||||
return $source->getCodebase()->methodExists($methodId);
|
||||
});
|
||||
|
||||
if (!in_array($method_name_lowercase, $methods)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ContainerResolver::resolvePsalmTypeFromApplicationContainerViaArgs($source->getNodeTypeProvider(), $call_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/psalm/psalm-plugin-symfony/issues/25
|
||||
* psalm needs to know about any classes that could be returned before analysis begins. This is a naive first approach
|
||||
*/
|
||||
public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event)
|
||||
{
|
||||
if (!in_array($event->getStorage()->name, ApplicationInterfaceProvider::getApplicationInterfaceClassLikes())) {
|
||||
|
@ -61,8 +61,6 @@ class Plugin implements PluginEntryPointInterface
|
||||
$registration->registerHooksFromClass(ReturnTypeProvider\RedirectReturnTypeProvider::class);
|
||||
require_once 'ReturnTypeProvider/ViewReturnTypeProvider.php';
|
||||
$registration->registerHooksFromClass(ReturnTypeProvider\ViewReturnTypeProvider::class);
|
||||
require_once 'ReturnTypeProvider/AppReturnTypeProvider.php';
|
||||
$registration->registerHooksFromClass(ReturnTypeProvider\AppReturnTypeProvider::class);
|
||||
require_once 'Handlers/Application/ContainerHandler.php';
|
||||
$registration->registerHooksFromClass(ContainerHandler::class);
|
||||
require_once 'Handlers/Application/OffsetHandler.php';
|
||||
|
@ -1,74 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Psalm\LaravelPlugin\ReturnTypeProvider;
|
||||
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\Internal\MethodIdentifier;
|
||||
use Psalm\LaravelPlugin\Providers\ApplicationProvider;
|
||||
use Psalm\LaravelPlugin\Util\ContainerResolver;
|
||||
use Psalm\Plugin\Hook\FunctionReturnTypeProviderInterface;
|
||||
use Psalm\Plugin\Hook\MethodReturnTypeProviderInterface;
|
||||
use Psalm\StatementsSource;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
use Psalm\Type\Union;
|
||||
use function get_class;
|
||||
use function array_filter;
|
||||
use function in_array;
|
||||
|
||||
final class AppReturnTypeProvider implements FunctionReturnTypeProviderInterface, MethodReturnTypeProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array<array-key, lowercase-string>
|
||||
*/
|
||||
public static function getFunctionIds(): array
|
||||
{
|
||||
return ['app', 'resolve'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<\PhpParser\Node\Arg> $call_args
|
||||
*/
|
||||
public static function getFunctionReturnType(StatementsSource $statements_source, string $function_id, array $call_args, Context $context, CodeLocation $code_location): ?Union
|
||||
{
|
||||
if (!$call_args) {
|
||||
return new Union([
|
||||
new TNamedObject(get_class(ApplicationProvider::getApp())),
|
||||
]);
|
||||
}
|
||||
|
||||
return ContainerResolver::resolvePsalmTypeFromApplicationContainerViaArgs($statements_source->getNodeTypeProvider(), $call_args) ?? Type::getMixed();
|
||||
}
|
||||
|
||||
public static function getClassLikeNames(): array
|
||||
{
|
||||
return [get_class(ApplicationProvider::getApp())];
|
||||
}
|
||||
|
||||
public static function getMethodReturnType(
|
||||
StatementsSource $source,
|
||||
string $fq_classlike_name,
|
||||
string $method_name_lowercase,
|
||||
array $call_args,
|
||||
Context $context,
|
||||
CodeLocation $code_location,
|
||||
?array $template_type_parameters = null,
|
||||
?string $called_fq_classlike_name = null,
|
||||
?string $called_method_name_lowercase = null
|
||||
) : ?Type\Union {
|
||||
// lumen doesn't have the likes of makeWith, so we will ensure these methods actually exist on the underlying
|
||||
// app contract
|
||||
$methods = array_filter(['make', 'makewith'], function (string $methodName) use ($source, $fq_classlike_name) {
|
||||
$methodId = new MethodIdentifier($fq_classlike_name, $methodName);
|
||||
return $source->getCodebase()->methodExists($methodId);
|
||||
});
|
||||
|
||||
if (!in_array($method_name_lowercase, $methods)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ContainerResolver::resolvePsalmTypeFromApplicationContainerViaArgs($source->getNodeTypeProvider(), $call_args);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user