Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to Psalm v5 #288

Open
wants to merge 16 commits into
base: 5.x
Choose a base branch
from
44 changes: 27 additions & 17 deletions src/Handler/ConsoleHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Atomic\TString;
use Psalm\Type\MutableUnion;
use Psalm\Type\Union;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -149,23 +148,29 @@ private static function analyseArgument(array $args, StatementsSource $statement
$mode = InputArgument::OPTIONAL;
}

$add_null = false;
if ($mode & InputArgument::IS_ARRAY) {
$returnTypes = new MutableUnion([new TArray([new Union([new TInt()]), new Union([new TString()])])]);
$returnTypes = [new TArray([new Union([new TInt()]), new Union([new TString()])])];
} elseif ($mode & InputArgument::REQUIRED) {
$returnTypes = new MutableUnion([new TString()]);
$returnTypes = [new TString()];
} else {
$returnTypes = new MutableUnion([new TString(), new TNull()]);
$add_null = true;
$returnTypes = [new TString()];
}

$defaultParam = $normalizedParams['default'];
if ($defaultParam) {
$returnTypes->removeType('null');
$add_null = false;
if ($defaultParam->value instanceof Expr\ConstFetch && 'null' === $defaultParam->value->name->parts[0]) {
$returnTypes->addType(new TNull());
$add_null = true;
}
}

self::$arguments[$identifier] = $returnTypes->freeze();
if ($add_null) {
$returnTypes[] = new TNull();
}

self::$arguments[$identifier] = new Union($returnTypes);
}

/**
Expand Down Expand Up @@ -200,40 +205,45 @@ private static function analyseOption(array $args, StatementsSource $statements_
$mode = InputOption::VALUE_OPTIONAL;
}

$returnTypes = new MutableUnion([new TString(), new TNull()]);
$add_null = true;
$returnTypes = [new TString()];

$defaultParam = $normalizedParams['default'];
if ($defaultParam) {
if (0 === ($mode & InputOption::VALUE_OPTIONAL)) {
$returnTypes->removeType('null');
$add_null = false;
}

if ($defaultParam->value instanceof Expr\ConstFetch) {
switch ($defaultParam->value->name->parts[0]) {
case 'null':
$returnTypes->addType(new TNull());
$add_null = true;
break;
case 'false':
case 'true':
$returnTypes->addType(new TBool());
$returnTypes[] = new TBool();
break;
}
}
}

if ($mode & InputOption::VALUE_NONE) {
$returnTypes = new MutableUnion([new TBool()]);
if ($mode & InputOption::VALUE_REQUIRED && $mode & InputOption::VALUE_IS_ARRAY) {
$add_null = false;
}

if ($mode & InputOption::VALUE_REQUIRED && $mode & InputOption::VALUE_IS_ARRAY) {
$returnTypes->removeType('null');
if ($add_null) {
$returnTypes[] = new TNull();
}

if ($mode & InputOption::VALUE_NONE) {
$returnTypes = [new TBool()];
}

if ($mode & InputOption::VALUE_IS_ARRAY) {
$returnTypes = new MutableUnion([new TArray([new Union([new TInt()]), $returnTypes->freeze()])]);
$returnTypes = [new TArray([new Union([new TInt()]), new Union($returnTypes)])];
}

self::$options[$identifier] = $returnTypes->freeze();
self::$options[$identifier] = new Union($returnTypes);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions src/Stubs/common/Component/HttpFoundation/Request.stubphp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ class Request
*
* @throws \LogicException
*
* @psalm-template TAsResource as bool
* @psalm-param TAsResource $asResource
* @psalm-return (TAsResource is true ? resource : string)
* @psalm-return (
* $asResource is true
* ? resource
* : string
* )
*/
public function getContent($asResource = false) {}

Expand Down
33 changes: 16 additions & 17 deletions tests/acceptance/acceptance/Tainting.feature
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,22 @@ Feature: Tainting
| query |
| cookies |

# todo: "@psalm-taint-source input" does not work on get() method
# Scenario: The user-agent is used in the body of a Response object
# Given I have the following code
# """
# class MyController
# {
# public function __invoke(Request $request): Response
# {
# return new Response($request->headers->get('user-agent'));
# }
# }
# """
# When I run Psalm with taint analysis
# Then I see these errors
# | Type | Message |
# | TaintedHtml | Detected tainted HTML |
# And I see no other errors
Scenario: The user-agent is used in the body of a Response object
Given I have the following code
"""
class MyController
{
public function __invoke(Request $request): Response
{
return new Response($request->headers->get('user-agent'));
}
}
"""
When I run Psalm with taint analysis
Then I see these errors
| Type | Message |
| TaintedHtml | Detected tainted HTML |
And I see no other errors

Scenario: All headers are printed in the body of a Response object
Given I have the following code
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/Symfony/TwigUtilsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function testItCanExtractTheTemplateNameFromAnExpression(string $expressi
{
$hasErrors = false;
$code = '<?php'."\n".$expression;
$statements = StatementsProvider::parseStatements($code, PHP_VERSION_ID, $hasErrors);
$statements = StatementsProvider::parseStatements($code, 7_01_00, $hasErrors);

$assertionHook = new class() implements AfterEveryFunctionCallAnalysisInterface {
public static function afterEveryFunctionCallAnalysis(AfterEveryFunctionCallAnalysisEvent $event): void
Expand Down Expand Up @@ -61,7 +61,7 @@ public function testItThrowsAnExceptionWhenTryingToExtractTemplateNameFromAnUnsu
{
$hasErrors = false;
$code = '<?php'."\n".'dummy(123);';
$statements = StatementsProvider::parseStatements($code, PHP_VERSION_ID, $hasErrors);
$statements = StatementsProvider::parseStatements($code, 7_01_00, $hasErrors);

$assertionHook = new class() implements AfterEveryFunctionCallAnalysisInterface {
public static function afterEveryFunctionCallAnalysis(AfterEveryFunctionCallAnalysisEvent $event): void
Expand Down