Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions conf/bleedingEdge.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ parameters:
internalTag: true
newStaticInAbstractClassStaticMethod: true
checkExtensionsForComparisonOperators: true
checkGenericIterableClasses: true
reportTooWideBool: true
rawMessageInBaseline: true
reportNestedTooWideType: false # tmp
Expand Down
1 change: 1 addition & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ parameters:
internalTag: false
newStaticInAbstractClassStaticMethod: false
checkExtensionsForComparisonOperators: false
checkGenericIterableClasses: false
reportTooWideBool: false
rawMessageInBaseline: false
reportNestedTooWideType: false
Expand Down
1 change: 1 addition & 0 deletions conf/parametersSchema.neon
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ parametersSchema:
internalTag: bool()
newStaticInAbstractClassStaticMethod: bool()
checkExtensionsForComparisonOperators: bool()
checkGenericIterableClasses: bool()
reportTooWideBool: bool()
rawMessageInBaseline: bool()
reportNestedTooWideType: bool()
Expand Down
10 changes: 9 additions & 1 deletion src/Rules/MissingTypehintCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public function __construct(
private bool $checkMissingCallableSignature,
#[AutowiredParameter(ref: '%featureToggles.skipCheckGenericClasses%')]
private array $skipCheckGenericClasses,
#[AutowiredParameter(ref: '%featureToggles.checkGenericIterableClasses%')]
private bool $checkGenericIterableClasses,
)
{
}
Expand Down Expand Up @@ -118,7 +120,13 @@ public function getNonGenericObjectTypesWithGenericClass(Type $type): array
if ($classReflection === null) {
return $type;
}
if (in_array($classReflection->getName(), self::ITERABLE_GENERIC_CLASS_NAMES, true)) {
if (
$classReflection->getName() === Traversable::class // already covered by getIterableTypesWithMissingValueTypehint
|| (
!$this->checkGenericIterableClasses &&
in_array($classReflection->getName(), self::ITERABLE_GENERIC_CLASS_NAMES, true)
)
) {
// checked by getIterableTypesWithMissingValueTypehint() already
return $type;
}
Expand Down
2 changes: 1 addition & 1 deletion stubs/PDOStatement.stub
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class PDOStatement implements Traversable, IteratorAggregate
public function getColumnMeta(int $column) {}

/**
* @return Iterator
* @return Iterator<mixed, array<int|string, mixed>>
*/
public function getIterator() {}
}
3 changes: 3 additions & 0 deletions stubs/runtime/ReflectionAttribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public function isRepeated(): bool
{
}

/**
* @return array<array-key, mixed>
*/
public function getArguments(): array
{
}
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug-8886.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ function testPDOStatementGetIterator(): void {
$pdo = new PDO('sqlite::memory:');
$stmt = $pdo->query('SELECT 1');

assertType('Iterator', $stmt->getIterator());
assertType('Iterator<mixed, array<int|string, mixed>>', $stmt->getIterator());
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ protected function getRule(): Rule
['GlobalTypeAlias' => 'int|string'],
self::createReflectionProvider(),
$container->getByType(TypeNodeResolver::class),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new ClassNameCheck(
new ClassCaseSensitivityCheck($reflectionProvider, true),
new ClassForbiddenNameCheck($container),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected function getRule(): Rule
['GlobalTypeAlias' => 'int|string'],
self::createReflectionProvider(),
$container->getByType(TypeNodeResolver::class),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new ClassNameCheck(
new ClassCaseSensitivityCheck($reflectionProvider, true),
new ClassForbiddenNameCheck($container),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected function getRule(): Rule
['GlobalTypeAlias' => 'int|string'],
self::createReflectionProvider(),
$container->getByType(TypeNodeResolver::class),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new ClassNameCheck(
new ClassCaseSensitivityCheck($reflectionProvider, true),
new ClassForbiddenNameCheck($container),
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/MethodTagRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): TRule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/MethodTagTraitRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): TRule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/MethodTagTraitUseRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protected function getRule(): TRule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
6 changes: 5 additions & 1 deletion tests/PHPStan/Rules/Classes/MixinRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protected function getRule(): Rule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down Expand Up @@ -69,6 +69,10 @@ public function testRule(): void
'PHPDoc tag @mixin contains generic class ReflectionClass but does not specify its types: T',
50,
],
[
'PHPDoc tag @mixin contains generic interface Iterator but does not specify its types: TKey, TValue',
50,
],
[
'PHPDoc tag @mixin contains unknown class MixinRule\UnknownestClass.',
50,
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/MixinTraitRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): Rule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/MixinTraitUseRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): Rule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/PropertyTagRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): TRule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Classes/PropertyTagTraitRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): TRule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): TRule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class MissingClassConstantTypehintRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new MissingClassConstantTypehintRule(new MissingTypehintCheck(true, []));
return new MissingClassConstantTypehintRule(new MissingTypehintCheck(true, [], true));
}

public function testRule(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class MissingFunctionParameterTypehintRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new MissingFunctionParameterTypehintRule(new MissingTypehintCheck(true, []));
return new MissingFunctionParameterTypehintRule(new MissingTypehintCheck(true, [], true));
}

public function testRule(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class MissingFunctionReturnTypehintRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new MissingFunctionReturnTypehintRule(new MissingTypehintCheck(true, []));
return new MissingFunctionReturnTypehintRule(new MissingTypehintCheck(true, [], true));
}

public function testRule(): void
Expand Down Expand Up @@ -58,6 +58,27 @@ public function testRule(): void
'Function MissingFunctionReturnTypehint\callableNestedNoPrototype() return type has no signature specified for callable.',
141,
],
[
'Function MissingFunctionReturnTypehint\returnsGeneratorOfIntegersNoPrototype() return type with generic class Generator does not specify its types: TKey, TValue, TSend, TReturn',
152,
],
[
'Function MissingFunctionReturnTypehint\returnsGeneratorOfIntegersByStringNoPrototype() return type with generic class Generator does not specify its types: TKey, TValue, TSend, TReturn',
169,
],
[
'Function MissingFunctionReturnTypehint\returnsIteratorNoPrototype() return type with generic interface Iterator does not specify its types: TKey, TValue',
186,
],
[
'Function MissingFunctionReturnTypehint\returnsIteratorAggregateNoPrototype() return type with generic interface IteratorAggregate does not specify its types: TKey, TValue',
199,
],
[
'Function MissingFunctionReturnTypehint\returnsTraversableNoPrototype() return type has no value type specified in iterable type Traversable.',
212,
MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,77 @@ function callableNestedNoPrototype() : callable{
function callableNestedWithPrototype() : callable{

}

function returnsGeneratorOfIntegersNoPrototype(): \Generator
{
yield 1;
yield 2;
yield 3;
}

/**
* @return \Generator<int, int>
*/
function returnsGeneratorOfIntegersWithPrototype(): \Generator
{
yield 1;
yield 2;
yield 3;
}

function returnsGeneratorOfIntegersByStringNoPrototype(): \Generator
{
yield '1' => 1;
yield '2' => 2;
yield '3' => 3;
}

/**
* @return \Generator<string, int>
*/
function returnsGeneratorOfIntegersByStringWithPrototype(): \Generator
{
yield '1' => 1;
yield '2' => 2;
yield '3' => 3;
}

function returnsIteratorNoPrototype(): \Iterator
{
yield 'test';
}

/**
* @return \Iterator<array-key,string>
*/
function returnsIteratorWithPrototype(): \Iterator
{
yield 'test';
}

function returnsIteratorAggregateNoPrototype(): \IteratorAggregate
{
return new \ArrayObject([]);
}

/**
* @return \IteratorAggregate<array-key,string>
*/
function returnsIteratorAggregateWithPrototype(): \IteratorAggregate
{
return new \ArrayObject([]);
}

function returnsTraversableNoPrototype(): \Traversable
{
yield 'test';
}

/**
* @return \Traversable<array-key,string>
*/
function returnsTraversableWithPrototype(): \Traversable
{
yield 'test';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class MissingMethodParameterTypehintRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new MissingMethodParameterTypehintRule(new MissingTypehintCheck(true, []));
return new MissingMethodParameterTypehintRule(new MissingTypehintCheck(true, [], true));
}

public function testRule(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class MissingMethodReturnTypehintRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new MissingMethodReturnTypehintRule(new MissingTypehintCheck(true, []));
return new MissingMethodReturnTypehintRule(new MissingTypehintCheck(true, [], true));
}

public function testRule(): void
Expand Down Expand Up @@ -54,6 +54,11 @@ public function testRule(): void
'Method MissingMethodReturnTypehint\CallableSignature::doFoo() return type has no signature specified for callable.',
99,
],
[
'Method MissingMethodReturnTypehint\IterableIntersection::doFoo() return type has no value type specified in iterable type Traversable.',
110,
MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP,
],
[
'Method MissingMethodReturnTypehint\Baz::returnsGenericWithSomeDefaults() return type with generic class MissingMethodReturnTypehint\GenericClassWithSomeDefaults does not specify its types: T, U (1-2 required)',
142,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class MissingMethodSelfOutTypeRuleTest extends RuleTestCase

protected function getRule(): TRule
{
return new MissingMethodSelfOutTypeRule(new MissingTypehintCheck(true, []));
return new MissingMethodSelfOutTypeRule(new MissingTypehintCheck(true, [], true));
}

public function testRule(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public function doFoo(): callable
class IterableIntersection
{

/** @return FooInterface[]|\Traversable */
/** @return FooInterface[]&\Traversable<array-key, FooInterface> */
public function doFoo(): \Traversable
{

Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/PhpDoc/FunctionAssertRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ protected function getRule(): Rule
$reflectionProvider,
$container,
),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new GenericObjectTypeCheck(),
true,
true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function getRule(): Rule
$container,
),
new GenericObjectTypeCheck(),
new MissingTypehintCheck(true, []),
new MissingTypehintCheck(true, [], true),
new UnresolvableTypeHelper(),
true,
true,
Expand Down
Loading
Loading