Skip to content

Commit

Permalink
Merge branch refs/heads/1.10.x into 1.11.x
Browse files Browse the repository at this point in the history
  • Loading branch information
phpstan-bot committed Nov 22, 2023
2 parents 713f7cd + c6898a1 commit 3a5328b
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ lint:
--exclude tests/PHPStan/Rules/Methods/data/bug-10101.php \
--exclude tests/PHPStan/Rules/Methods/data/final-method-by-phpdoc.php \
--exclude tests/PHPStan/Rules/Traits/data/conflicting-trait-constants-types.php \
--exclude tests/PHPStan/Rules/Types/data/invalid-union-with-mixed.php \
--exclude tests/PHPStan/Rules/Types/data/invalid-union-with-never.php \
--exclude tests/PHPStan/Rules/Types/data/invalid-union-with-void.php \
--exclude tests/PHPStan/Rules/Constants/data/dynamic-class-constant-fetch.php \
src tests

Expand Down
1 change: 1 addition & 0 deletions conf/config.level0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ rules:
- PHPStan\Rules\Properties\ReadOnlyPropertyRule
- PHPStan\Rules\Traits\ConflictingTraitConstantsRule
- PHPStan\Rules\Traits\ConstantsInTraitsRule
- PHPStan\Rules\Types\InvalidTypesInUnionRule
- PHPStan\Rules\Variables\UnsetRule
- PHPStan\Rules\Whitespace\FileWhitespaceRule

Expand Down
115 changes: 115 additions & 0 deletions src/Rules/Types/InvalidTypesInUnionRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Types;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\ClassPropertyNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use function array_merge;
use function in_array;
use function sprintf;

/**
* @implements Rule<Node>
*/
class InvalidTypesInUnionRule implements Rule
{

private const ONLY_STANDALONE_TYPES = [
'mixed',
'never',
'void',
];

public function getNodeType(): string
{
return Node::class;
}

public function processNode(Node $node, Scope $scope): array
{
if (!$node instanceof Node\FunctionLike && !$node instanceof ClassPropertyNode) {
return [];
}

if ($node instanceof Node\FunctionLike) {
return $this->processFunctionLikeNode($node);

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.1)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.3, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.2, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.3, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 39 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.2, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.
}

return $this->processClassPropertyNode($node);

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.1)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.3, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.2, ubuntu-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.3, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.

Check failure on line 42 in src/Rules/Types/InvalidTypesInUnionRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.2, windows-latest)

Method PHPStan\Rules\Types\InvalidTypesInUnionRule::processNode() should return list<PHPStan\Rules\IdentifierRuleError> but returns list<PHPStan\Rules\RuleError>.
}

/**
* @return list<RuleError>
*/
private function processFunctionLikeNode(Node\FunctionLike $functionLike): array
{
$errors = [];

foreach ($functionLike->getParams() as $param) {
if (!$param->type instanceof Node\ComplexType) {
continue;
}

$errors = array_merge($errors, $this->processComplexType($param->type));
}

if ($functionLike->getReturnType() instanceof Node\ComplexType) {
$errors = array_merge($errors, $this->processComplexType($functionLike->getReturnType()));
}

return $errors;
}

/**
* @return list<RuleError>
*/
private function processClassPropertyNode(ClassPropertyNode $classPropertyNode): array
{
if (!$classPropertyNode->getNativeType() instanceof Node\ComplexType) {
return [];
}

return $this->processComplexType($classPropertyNode->getNativeType());
}

/**
* @return list<RuleError>
*/
private function processComplexType(Node\ComplexType $complexType): array
{
if (!$complexType instanceof Node\UnionType && !$complexType instanceof Node\NullableType) {
return [];
}

if ($complexType instanceof Node\UnionType) {
foreach ($complexType->types as $type) {
if ($type instanceof Node\Identifier && in_array($type->toString(), self::ONLY_STANDALONE_TYPES, true)) {
return [
RuleErrorBuilder::message(sprintf('Type %s cannot be part of a union type declaration.', $type->toString()))
->line($complexType->getLine())
->nonIgnorable()
->build(),
];
}
}

return [];
}

if ($complexType->type instanceof Node\Identifier && in_array($complexType->type->toString(), self::ONLY_STANDALONE_TYPES, true)) {
return [
RuleErrorBuilder::message(sprintf('Type %s cannot be part of a nullable type declaration.', $complexType->type->toString()))
->line($complexType->getLine())
->nonIgnorable()
->build(),
];
}

return [];
}

}
91 changes: 91 additions & 0 deletions tests/PHPStan/Rules/Types/InvalidTypesInUnionRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Types;

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<InvalidTypesInUnionRule>
*/
class InvalidTypesInUnionRuleTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new InvalidTypesInUnionRule();
}

public function testRuleOnUnionWithVoid(): void
{
$this->analyse([__DIR__ . '/data/invalid-union-with-void.php'], [
[
'Type void cannot be part of a union type declaration.',
11,
],
[
'Type void cannot be part of a nullable type declaration.',
15,
],
]);
}

/**
* @requires PHP 8.0
*/
public function testRuleOnUnionWithMixed(): void
{
$this->analyse([__DIR__ . '/data/invalid-union-with-mixed.php'], [
[
'Type mixed cannot be part of a nullable type declaration.',
9,
],
[
'Type mixed cannot be part of a union type declaration.',
12,
],
[
'Type mixed cannot be part of a union type declaration.',
16,
],
[
'Type mixed cannot be part of a union type declaration.',
17,
],
[
'Type mixed cannot be part of a union type declaration.',
22,
],
[
'Type mixed cannot be part of a nullable type declaration.',
29,
],
[
'Type mixed cannot be part of a nullable type declaration.',
29,
],
[
'Type mixed cannot be part of a nullable type declaration.',
34,
],
]);
}

/**
* @requires PHP 8.1
*/
public function testRuleOnUnionWithNever(): void
{
$this->analyse([__DIR__ . '/data/invalid-union-with-never.php'], [
[
'Type never cannot be part of a nullable type declaration.',
7,
],
[
'Type never cannot be part of a union type declaration.',
16,
],
]);
}

}
34 changes: 34 additions & 0 deletions tests/PHPStan/Rules/Types/data/invalid-union-with-mixed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace InvalidUnionWithMixed;

class Foo
{

public ?string $bar = null;
public ?mixed $baz = null;

public int|null $lorem = null;
public mixed|string $ipsum = '';

public function dolor(
string|int $sit,
bool|mixed $amet
): mixed|string
{
return '';
}

public function lorem(): mixed|string
{
return '';
}

}

function funcWithMixed(mixed $a, ?mixed $b): ?mixed
{
return $a;
}

static fn (int $a): ?mixed => $a;
24 changes: 24 additions & 0 deletions tests/PHPStan/Rules/Types/data/invalid-union-with-never.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

namespace InvalidUnionWithNever;

class Foo
{
public function bar(string $a): ?never
{
if ($a === null) {
return null;
}

throw new \RuntimeException($a);
}

public function baz(string $b): never|string
{
if ($b === '') {
throw new \RuntimeException('Error.');
}

return $b;
}
}
19 changes: 19 additions & 0 deletions tests/PHPStan/Rules/Types/data/invalid-union-with-void.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace InvalidUnionWithVoid;

class Foo
{

public function prepare(
string $query,
string ...$args
): string|void
{
}

public function execute(string $query): ?void
{
}

}

0 comments on commit 3a5328b

Please sign in to comment.