mirror of
https://github.com/danog/psalm-plugin-symfony.git
synced 2024-11-26 20:04:58 +01:00
[feature] request getContent return type fix (#5)
This commit is contained in:
parent
b1c05203bc
commit
c2924cb89a
@ -9,6 +9,12 @@ composer require --dev seferov/symfony-psalm-plugin
|
||||
vendor/bin/psalm-plugin enable seferov/symfony-psalm-plugin
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
- Fixes `PossiblyInvalidArgument` for `Symfony\Component\HttpFoundation\Request::getContent`.
|
||||
The plugin calculates real return type by checking the given argument and marks return type as either string or resource.
|
||||
- Complains when `Container` is injected to a service. Use dependency-injection.
|
||||
|
||||
### Credits
|
||||
|
||||
- [@weirdan](https://github.com/weirdan) for [codeception psalm module](https://github.com/weirdan/codeception-psalm-module)
|
||||
|
@ -5,12 +5,9 @@ namespace Seferov\SymfonyPsalmPlugin\Handler;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\FileManipulation;
|
||||
use Psalm\IssueBuffer;
|
||||
use Psalm\Plugin\Hook\AfterClassLikeAnalysisInterface;
|
||||
use Psalm\Plugin\Hook\AfterMethodCallAnalysisInterface;
|
||||
@ -24,11 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
class ClassHandler implements AfterClassLikeAnalysisInterface, AfterMethodCallAnalysisInterface
|
||||
{
|
||||
/**
|
||||
* Called after a statement has been checked
|
||||
*
|
||||
* @param FileManipulation[] $file_replacements
|
||||
*
|
||||
* @return null|false
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function afterStatementAnalysis(Node\Stmt\ClassLike $stmt, ClassLikeStorage $classlike_storage, StatementsSource $statements_source, Codebase $codebase, array &$file_replacements = [])
|
||||
{
|
||||
@ -49,10 +42,7 @@ class ClassHandler implements AfterClassLikeAnalysisInterface, AfterMethodCallAn
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall|StaticCall $expr
|
||||
* @param FileManipulation[] $file_replacements
|
||||
*
|
||||
* @return void
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function afterMethodCallAnalysis(
|
||||
Expr $expr,
|
||||
@ -65,20 +55,26 @@ class ClassHandler implements AfterClassLikeAnalysisInterface, AfterMethodCallAn
|
||||
array &$file_replacements = [],
|
||||
Union &$return_type_candidate = null
|
||||
) {
|
||||
if (!$expr instanceof MethodCall) {
|
||||
return;
|
||||
}
|
||||
switch ($declaring_method_id) {
|
||||
case 'Doctrine\ORM\EntityManagerInterface::getrepository':
|
||||
if (!$expr->args[0]->value instanceof ClassConstFetch) {
|
||||
IssueBuffer::accepts(
|
||||
new RepositoryStringShortcut(new CodeLocation($statements_source, $expr->args[0]->value)),
|
||||
$statements_source->getSuppressedIssues()
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
if ($expr->name instanceof Node\Identifier && 'getRepository' === $expr->name->name) {
|
||||
/** @psalm-suppress InternalMethod */
|
||||
$methodStorage = $codebase->methods->getStorage($declaring_method_id);
|
||||
|
||||
if ('Doctrine\ORM\EntityManagerInterface' === $methodStorage->defining_fqcln && !$expr->args[0]->value instanceof ClassConstFetch) {
|
||||
IssueBuffer::accepts(
|
||||
new RepositoryStringShortcut(new CodeLocation($statements_source, $expr->args[0]->value)),
|
||||
$statements_source->getSuppressedIssues()
|
||||
);
|
||||
}
|
||||
case 'Symfony\Component\HttpFoundation\Request::getcontent':
|
||||
if ($return_type_candidate) {
|
||||
$removeType = 'resource';
|
||||
if (isset($expr->args[0]->value->name->parts[0])) {
|
||||
/** @psalm-suppress MixedArrayAccess */
|
||||
$removeType = 'true' === $expr->args[0]->value->name->parts[0] ? 'string' : 'resource';
|
||||
}
|
||||
$return_type_candidate->removeType($removeType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,6 @@ class ContainerDependency extends CodeIssue
|
||||
{
|
||||
public function __construct(CodeLocation $code_location)
|
||||
{
|
||||
parent::__construct('Container must not inject into services as dependency!', $code_location);
|
||||
parent::__construct('Container must not inject into services as dependency! Use dependency-injection.', $code_location);
|
||||
}
|
||||
}
|
||||
|
74
tests/acceptance/RequestContent.feature
Normal file
74
tests/acceptance/RequestContent.feature
Normal file
@ -0,0 +1,74 @@
|
||||
Feature: Request getContent
|
||||
Symfony Request has getContent method on which return type changes based on argument
|
||||
|
||||
Background:
|
||||
Given I have the following config
|
||||
"""
|
||||
<?xml version="1.0"?>
|
||||
<psalm totallyTyped="true">
|
||||
<projectFiles>
|
||||
<directory name="."/>
|
||||
<ignoreFiles> <directory name="../../vendor"/> </ignoreFiles>
|
||||
</projectFiles>
|
||||
|
||||
<plugins>
|
||||
<pluginClass class="Seferov\SymfonyPsalmPlugin\Plugin"/>
|
||||
</plugins>
|
||||
</psalm>
|
||||
"""
|
||||
|
||||
Scenario: Asserting '$request->getContent()' without any argument returns string
|
||||
Given I have the following code
|
||||
"""
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class App
|
||||
{
|
||||
public function index(Request $request): void
|
||||
{
|
||||
json_decode($request->getContent());
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see no errors
|
||||
|
||||
Scenario: Asserting '$request->getContent(false)' returns string
|
||||
Given I have the following code
|
||||
"""
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class App
|
||||
{
|
||||
public function index(Request $request): void
|
||||
{
|
||||
json_decode($request->getContent(false));
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see no errors
|
||||
|
||||
Scenario: Asserting '$request->getContent(true)' returns resource
|
||||
Given I have the following code
|
||||
"""
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class App
|
||||
{
|
||||
public function index(Request $request): void
|
||||
{
|
||||
json_decode($request->getContent(true));
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see these errors
|
||||
| Type | Message |
|
||||
| InvalidArgument | Argument 1 of json_decode expects string, resource provided |
|
Loading…
Reference in New Issue
Block a user