Skip to content

Commit 6c6b4f5

Browse files
authored
Support Psalm v4.0 (#98)
* Support Psalm v4.0 * no message * no message * no message
1 parent 720e554 commit 6c6b4f5

12 files changed

+54
-32
lines changed

.github/workflows/integrate.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
restore-keys: php-${{ matrix.php-version }}-psalm-
6262

6363
- name: "Run vimeo/psalm"
64-
run: vendor/bin/psalm --find-dead-code --find-unused-psalm-suppress --diff --diff-methods --shepherd --show-info=false --stats --output-format=github
64+
run: vendor/bin/psalm --find-dead-code --find-unused-psalm-suppress --shepherd --show-info=false --stats --output-format=github
6565

6666
tests:
6767
name: "Tests"
@@ -71,10 +71,9 @@ jobs:
7171
strategy:
7272
matrix:
7373
php-version:
74-
- 7.1
75-
- 7.2
7674
- 7.3
7775
- 7.4
76+
- nightly
7877

7978
symfony-version:
8079
- 3

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
}
1111
],
1212
"require": {
13-
"php": "^7.1",
13+
"php": "^7.3 || ^8.0",
1414
"ext-simplexml": "*",
1515
"symfony/framework-bundle": "^3.0 || ^4.0 || ^5.0",
16-
"vimeo/psalm": "^3.17"
16+
"vimeo/psalm": "^4.0"
1717
},
1818
"require-dev": {
1919
"doctrine/orm": "^2.7",

src/Handler/ConsoleHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public static function afterMethodCallAnalysis(
5050
Codebase $codebase,
5151
array &$file_replacements = [],
5252
Union &$return_type_candidate = null
53-
) {
53+
): void {
5454
switch ($declaring_method_id) {
5555
case 'Symfony\Component\Console\Command\Command::addargument':
5656
self::analyseArgument($expr->args, $statements_source);

src/Handler/ContainerDependencyHandler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public static function afterStatementAnalysis(
2323
StatementsSource $statements_source,
2424
Codebase $codebase,
2525
array &$file_replacements = []
26-
) {
26+
): ?bool {
2727
if ($stmt instanceof Node\Stmt\ClassMethod && '__construct' === $stmt->name->name) {
2828
foreach ($stmt->params as $param) {
2929
if ($param->type instanceof Node\Name && ContainerInterface::class === $param->type->getAttribute('resolvedName')) {
@@ -34,5 +34,7 @@ public static function afterStatementAnalysis(
3434
}
3535
}
3636
}
37+
38+
return null;
3739
}
3840
}

src/Handler/ContainerHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public static function afterMethodCallAnalysis(
5454
Codebase $codebase,
5555
array &$file_replacements = [],
5656
Union &$return_type_candidate = null
57-
) {
57+
): void {
5858
if (!self::isContainerMethod($declaring_method_id, 'get')) {
5959
if (self::isContainerMethod($declaring_method_id, 'getparameter')) {
6060
$argument = $expr->args[0]->value;

src/Handler/DoctrineRepositoryHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static function afterMethodCallAnalysis(
3737
Codebase $codebase,
3838
array &$file_replacements = [],
3939
Union &$return_type_candidate = null
40-
) {
40+
): void {
4141
if (in_array($declaring_method_id, ['Doctrine\ORM\EntityManagerInterface::getrepository', 'Doctrine\Persistence\ObjectManager::getrepository'])) {
4242
$entityName = $expr->args[0]->value;
4343
if ($entityName instanceof String_) {

src/Handler/HeaderBagHandler.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Psalm\Context;
99
use Psalm\Plugin\Hook\MethodReturnTypeProviderInterface;
1010
use Psalm\StatementsSource;
11+
use Psalm\Type;
1112
use Psalm\Type\Atomic\TArray;
1213
use Psalm\Type\Atomic\TInt;
1314
use Psalm\Type\Atomic\TNull;
@@ -25,8 +26,17 @@ public static function getClassLikeNames(): array
2526
];
2627
}
2728

28-
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)
29-
{
29+
public static function getMethodReturnType(
30+
StatementsSource $source,
31+
string $fq_classlike_name,
32+
string $method_name_lowercase,
33+
array $call_args,
34+
Context $context,
35+
CodeLocation $code_location,
36+
?array $template_type_parameters = null,
37+
?string $called_fq_classlike_name = null,
38+
?string $called_method_name_lowercase = null
39+
): ?Type\Union {
3040
if (HeaderBag::class !== $fq_classlike_name) {
3141
return null;
3242
}

src/Plugin.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected function getStubsForMajorVersion(int $majorVersion): array
4747
/**
4848
* {@inheritdoc}
4949
*/
50-
public function __invoke(RegistrationInterface $api, SimpleXMLElement $config = null)
50+
public function __invoke(RegistrationInterface $api, SimpleXMLElement $config = null): void
5151
{
5252
require_once __DIR__.'/Handler/HeaderBagHandler.php';
5353
require_once __DIR__.'/Handler/ContainerHandler.php';

src/Twig/CachedTemplatesTainter.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,23 @@ public static function getClassLikeNames(): array
3030
return [Environment::class];
3131
}
3232

33-
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): void
34-
{
33+
public static function getMethodReturnType(
34+
StatementsSource $source,
35+
string $fq_classlike_name,
36+
string $method_name_lowercase,
37+
array $call_args,
38+
Context $context,
39+
CodeLocation $code_location,
40+
?array $template_type_parameters = null,
41+
?string $called_fq_classlike_name = null,
42+
?string $called_method_name_lowercase = null
43+
): ?Union {
3544
if (!$source instanceof StatementsAnalyzer) {
3645
throw new RuntimeException(sprintf('The %s::%s hook can only be called using a %s.', __CLASS__, __METHOD__, StatementsAnalyzer::class));
3746
}
3847

3948
if ('render' !== $method_name_lowercase) {
40-
return;
49+
return null;
4150
}
4251

4352
$fake_method_call = new MethodCall(
@@ -52,7 +61,7 @@ public static function getMethodReturnType(StatementsSource $source, string $fq_
5261

5362
$firstArgument = $call_args[0]->value;
5463
if (!$firstArgument instanceof String_) {
55-
return;
64+
return null;
5665
}
5766

5867
$cacheClassName = CachedTemplatesMapping::getCacheClassName($firstArgument->value);
@@ -66,5 +75,7 @@ public static function getMethodReturnType(StatementsSource $source, string $fq_
6675
$fake_method_call,
6776
$context
6877
);
78+
79+
return null;
6980
}
7081
}

src/Twig/Context.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
use Psalm\CodeLocation;
88
use Psalm\Internal\Codebase\TaintFlowGraph;
9-
use Psalm\Internal\ControlFlow\ControlFlowNode;
10-
use Psalm\Internal\ControlFlow\TaintSink;
11-
use Psalm\Internal\ControlFlow\TaintSource;
9+
use Psalm\Internal\DataFlow\DataFlowNode;
10+
use Psalm\Internal\DataFlow\TaintSink;
11+
use Psalm\Internal\DataFlow\TaintSource;
1212
use Psalm\Type\TaintKind;
1313
use Twig\Node\Expression\FilterExpression;
1414
use Twig\Node\Expression\NameExpression;
@@ -18,10 +18,10 @@
1818

1919
class Context
2020
{
21-
/** @var array<string, ControlFlowNode> */
21+
/** @var array<string, DataFlowNode> */
2222
private $unassignedVariables = [];
2323

24-
/** @var array<string, ControlFlowNode> */
24+
/** @var array<string, DataFlowNode> */
2525
private $localVariables = [];
2626

2727
/** @var Source */
@@ -36,7 +36,7 @@ public function __construct(Source $sourceContext, TaintFlowGraph $taint)
3636
$this->taint = $taint;
3737
}
3838

39-
public function addSink(Node $node, ControlFlowNode $source): void
39+
public function addSink(Node $node, DataFlowNode $source): void
4040
{
4141
$codeLocation = $this->getNodeLocation($node);
4242

@@ -59,7 +59,7 @@ public function addSink(Node $node, ControlFlowNode $source): void
5959
$this->taint->addPath($source, $sink, 'arg');
6060
}
6161

62-
public function taintVariable(NameExpression $expression): ControlFlowNode
62+
public function taintVariable(NameExpression $expression): DataFlowNode
6363
{
6464
/** @var string $variableName */
6565
$variableName = $expression->getAttribute('name');
@@ -72,7 +72,7 @@ public function taintVariable(NameExpression $expression): ControlFlowNode
7272
return $this->addVariableUsage($variableName, $sinkNode);
7373
}
7474

75-
public function getTaintDestination(ControlFlowNode $taintSource, FilterExpression $expression): ControlFlowNode
75+
public function getTaintDestination(DataFlowNode $taintSource, FilterExpression $expression): DataFlowNode
7676
{
7777
/** @var string $filterName */
7878
$filterName = $expression->getNode('filter')->getAttribute('value');
@@ -117,7 +117,7 @@ public function taintUnassignedVariables(string $templateName): void
117117
}
118118
}
119119

120-
private function addVariableTaintNode(NameExpression $variableNode): ControlFlowNode
120+
private function addVariableTaintNode(NameExpression $variableNode): DataFlowNode
121121
{
122122
/** @var string $variableName */
123123
$variableName = $variableNode->getAttribute('name');
@@ -128,7 +128,7 @@ private function addVariableTaintNode(NameExpression $variableNode): ControlFlow
128128
return $taintNode;
129129
}
130130

131-
private function addVariableUsage(string $variableName, ControlFlowNode $variableTaint): ControlFlowNode
131+
private function addVariableUsage(string $variableName, DataFlowNode $variableTaint): DataFlowNode
132132
{
133133
if (!isset($this->localVariables[$variableName])) {
134134
return $this->unassignedVariables[$variableName] = $variableTaint;

src/Twig/PrintNodeAnalyzer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Psalm\SymfonyPsalmPlugin\Twig;
66

7-
use Psalm\Internal\ControlFlow\ControlFlowNode;
7+
use Psalm\Internal\DataFlow\DataFlowNode;
88
use RuntimeException;
99
use Twig\Node\Expression\AbstractExpression;
1010
use Twig\Node\Expression\FilterExpression;
@@ -47,7 +47,7 @@ private function expressionIsEscaped(AbstractExpression $expression): bool
4747
return false;
4848
}
4949

50-
private function getTaintSource(AbstractExpression $expression): ?ControlFlowNode
50+
private function getTaintSource(AbstractExpression $expression): ?DataFlowNode
5151
{
5252
if ($expression instanceof FilterExpression) {
5353
/** @var AbstractExpression $filteredExpression */

src/Twig/TemplateFileAnalyzer.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Psalm\Context as PsalmContext;
88
use Psalm\Internal\Analyzer\FileAnalyzer;
9-
use Psalm\Internal\ControlFlow\TaintSource;
9+
use Psalm\Internal\DataFlow\DataFlowNode;
1010
use Twig\Environment;
1111
use Twig\Loader\FilesystemLoader;
1212
use Twig\NodeTraverser;
@@ -17,7 +17,7 @@ public function analyze(
1717
PsalmContext $file_context = null,
1818
bool $preserve_analyzers = false,
1919
PsalmContext $global_context = null
20-
) {
20+
): void {
2121
$codebase = $this->project_analyzer->getCodebase();
2222
$taint = $codebase->taint_flow_graph;
2323

@@ -52,9 +52,9 @@ public function analyze(
5252
public static function getTaintNodeForTwigNamedVariable(
5353
string $template_id,
5454
string $variable_name
55-
): TaintSource {
55+
): DataFlowNode {
5656
$label = $arg_id = strtolower($template_id).'#'.strtolower($variable_name);
5757

58-
return new TaintSource($arg_id, $label, null, null);
58+
return new DataFlowNode($arg_id, $label, null, null);
5959
}
6060
}

0 commit comments

Comments
 (0)