fix: add classes that can be returned by the container to be scanned

This commit is contained in:
fiachra mcdermott 2021-06-15 11:45:42 -07:00
parent e8dd02d93f
commit 46ef7e8882
4 changed files with 39 additions and 8 deletions

View File

@ -2,9 +2,13 @@
namespace Psalm\LaravelPlugin;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Foundation\Application;
use PhpParser;
use Psalm\Context;
use Psalm\CodeLocation;
use Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface;
use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;
use Psalm\Type;
use Psalm\StatementsSource;
use function get_class;
@ -13,7 +17,8 @@ class AppInterfaceProvider implements
\Psalm\Plugin\Hook\MethodReturnTypeProviderInterface,
\Psalm\Plugin\Hook\MethodExistenceProviderInterface,
\Psalm\Plugin\Hook\MethodVisibilityProviderInterface,
\Psalm\Plugin\Hook\MethodParamsProviderInterface
\Psalm\Plugin\Hook\MethodParamsProviderInterface,
AfterClassLikeVisitInterface
{
/** @return array<string> */
public static function getClassLikeNames() : array
@ -76,7 +81,7 @@ class AppInterfaceProvider implements
if ($statements_source) {
if ($method_name_lowercase === 'offsetget' || $method_name_lowercase === 'offsetset') {
return $statements_source->getCodebase()->getMethodParams(
get_class(ApplicationHelper::getApp()) . '::' . $method_name_lowercase
ApplicationHelper::getAppFullyQualifiedClassName() . '::' . $method_name_lowercase
);
}
}
@ -105,11 +110,32 @@ class AppInterfaceProvider implements
if ($method_name_lowercase === 'offsetset') {
return $source->getCodebase()->getMethodReturnType(
get_class(ApplicationHelper::getApp()) . '::' . $method_name_lowercase,
ApplicationHelper::getAppFullyQualifiedClassName() . '::' . $method_name_lowercase,
$fq_classlike_name
);
}
return null;
}
public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event)
{
// @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
if (in_array($event->getStorage()->name, self::getClassLikeNames())) {
$appClassName = ApplicationHelper::getAppFullyQualifiedClassName();
$classesThatCouldBeReturnedThatArentReferencedAlready = array_merge(
[$appClassName],
array_values(AliasLoader::getInstance()->getAliases()),
);
foreach ($classesThatCouldBeReturnedThatArentReferencedAlready as $className) {
$filePath = $event->getStatementsSource()->getFilePath();
$fileStorage = $event->getCodebase()->file_storage_provider->get($filePath);
$fileStorage->referenced_classlikes[strtolower($className)] = $className;
$event->getCodebase()->queueClassLikeForScanning($className);
}
}
}
}

View File

@ -56,6 +56,14 @@ final class ApplicationHelper
return $app;
}
/**
* @psalm-return class-string
*/
public static function getAppFullyQualifiedClassName(): string
{
return get_class(self::getApp());
}
/**
* Resolve application bootstrapper.
*

View File

@ -135,7 +135,7 @@ class Plugin implements PluginEntryPointInterface
new \Symfony\Component\Console\Input\ArrayInput([]),
new \Symfony\Component\Console\Output\NullOutput()
);
$registration->addStubFile($cache_dir . 'meta.stubphp');
}

View File

@ -136,7 +136,4 @@ Feature: Container
}
"""
When I run Psalm
Then I see these errors
| Type | Message |
| InvalidReturnType | The declared return type 'Illuminate\Log\LogManager' for testMakeWith is incorrect, got 'logg' |
| InvalidReturnStatement | The inferred type 'logg' does not match the declared return type 'Illuminate\Log\LogManager' for testMakeWith |
Then I see exit code 2