Skip to content
Closed
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
294 changes: 294 additions & 0 deletions phpstan-baseline.neon

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions src/Rules/RuleLevelHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,30 @@ public function isThis(Expr $expression): bool

private function transformCommonType(Type $type): Type
{
if (!$this->checkExplicitMixed && !$this->checkImplicitMixed) {
if (!$this->checkExplicitMixed && !$this->checkImplicitMixed && $type instanceof MixedType) {
return $type;
}

return TypeTraverser::map($type, function (Type $type, callable $traverse) {
$isTopLevel = true;
return TypeTraverser::map($type, function (Type $type, callable $traverse) use (&$isTopLevel) {
if ($type instanceof TemplateMixedType) {
if ($this->checkExplicitMixed) {
return $type->toStrictMixedType();
}
}
if (
$type instanceof MixedType
&& !$type instanceof TemplateMixedType
&& (
($type->isExplicitMixed() && $this->checkExplicitMixed)
|| (!$type->isExplicitMixed() && $this->checkImplicitMixed)
|| (!$type->isExplicitMixed() && !$isTopLevel)
)
) {
return new StrictMixedType();
}

$isTopLevel = false;
return $traverse($type);
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/Testing/TypeInferenceTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ protected static function getEarlyTerminatingMethodCalls(): array
return [];
}

/** @return string[] */
/** @return list<string> */
protected static function getEarlyTerminatingFunctionCalls(): array
{
return [];
Expand Down
7 changes: 6 additions & 1 deletion tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool

public function testRule(): void
{
$this->analyse([__DIR__ . '/data/bug-9307.php'], []);
$this->analyse([__DIR__ . '/data/bug-9307.php'], [
[
'Parameter #1 $objects of method Bug9307\Aaa::acceptObjects() expects array<int, Bug9307\Item>, array<mixed> given.',
36,
],
]);
}

}
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ protected static function getEarlyTerminatingMethodCalls(): array
];
}

/** @return list<string> */
protected static function getEarlyTerminatingFunctionCalls(): array
{
return ['baz'];
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ protected static function getEarlyTerminatingMethodCalls(): array
];
}

/** @return list<string> */
protected static function getEarlyTerminatingFunctionCalls(): array
{
return ['baz'];
Expand Down
15 changes: 12 additions & 3 deletions tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1283,13 +1283,13 @@ public function testDiscussion7450WithCheckExplicitMixed(): void
'Parameter #1 $foo of function Discussion7450\foo expects array{policy: non-empty-string, entitlements: array<non-empty-string>}, array{policy: mixed, entitlements: mixed} given.',
18,
"• Offset 'policy' (non-empty-string) does not accept type mixed.
• Offset 'entitlements' (array<non-empty-string>) does not accept type mixed.",
• Offset 'entitlements' (array<int|string, non-empty-string>) does not accept type mixed.",
],
[
'Parameter #1 $foo of function Discussion7450\foo expects array{policy: non-empty-string, entitlements: array<non-empty-string>}, array{policy: mixed, entitlements: mixed} given.',
28,
"• Offset 'policy' (non-empty-string) does not accept type mixed.
• Offset 'entitlements' (array<non-empty-string>) does not accept type mixed.",
• Offset 'entitlements' (array<int|string, non-empty-string>) does not accept type mixed.",
],
]);
}
Expand Down Expand Up @@ -1429,6 +1429,10 @@ public function testCurlSetOpt(): void
'Parameter #3 $value of function curl_setopt expects non-empty-string|null, \'\' given.',
34,
],
[
'Parameter #3 $value of function curl_setopt expects array<int, string>, array given.',
44,
],
[
'Parameter #3 $value of function curl_setopt expects array<int, string>, array<string, string> given.',
77,
Expand Down Expand Up @@ -2201,7 +2205,12 @@ public function testBug9167(): void

public function testBug3107(): void
{
$this->analyse([__DIR__ . '/data/bug-3107.php'], []);
$this->analyse([__DIR__ . '/data/bug-3107.php'], [
[
'Parameter #1 $a of function Bug3107\take expects array<string, int>, array<int> given.',
19,
],
]);
}

public function testBug12676(): void
Expand Down
14 changes: 13 additions & 1 deletion tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public function testBug6568(): void
[
'Function Bug6568\test() should return T of array but returns array<mixed, mixed>.',
12,
'Type array<mixed, mixed> is not always the same as T. It breaks the contract for some argument types, typically subtypes.',
'Type array<int|string, mixed> is not always the same as T. It breaks the contract for some argument types, typically subtypes.',
],
]);
}
Expand Down Expand Up @@ -438,4 +438,16 @@ public function testBug14428(): void
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-14428.php'], []);
}

public function testBug8681(): void
{
$this->checkNullables = true;
$this->checkExplicitMixed = false;
$this->analyse([__DIR__ . '/data/bug-8681.php'], [
[
'Function Bug8681Functions\test() should return array<string, string> but returns array.',
12,
],
]);
}

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

namespace Bug8681Functions;

/**
* @return array<string, string>
*/
function test(): array
{
/** @var array $a */
$a = [];
return $a;
}

function testClosure(): void
{
/** @var array $a */
$a = [];

/**
* @return array<string, string>
*/
$closure = function () use ($a): array {
return $a;
};

$closure();
}
41 changes: 39 additions & 2 deletions tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,10 @@ public function testCallMethods(): void
'Call to an undefined method Test\ArraySliceWithNonEmptyArray::doesNotExist().',
1092,
],
[
'Parameter #1 $as of method Test\AssertInForeach::doBar() expects array<Test\AssertInForeach>, list<mixed> given.',
1177,
],
[
'Call to an undefined method Test\AssertInFor::doBar().',
1207,
Expand All @@ -486,6 +490,14 @@ public function testCallMethods(): void
1285,
'Type int|string has already been eliminated from mixed.',
],
[
'Parameter #2 $y of method Test\NonEmptyArrayAcceptsBug::doBaz() expects array<stdClass>, array given.',
1332,
],
[
'Parameter #2 $y of method Test\NonEmptyArrayAcceptsBug::doLorem() expects iterable<stdClass>, array given.',
1333,
],
[
'Parameter #2 $b of method Test\ExpectsExceptionGenerics::expectsExceptionUpperBound() expects Exception, Throwable given.',
1378,
Expand Down Expand Up @@ -561,6 +573,10 @@ public function testCallMethods(): void
'Parameter #1 $code of method Test\\ValueOfParam::foo() expects \'John F. Kennedy…\'|\'La Guardia Airport\', \'Newark Liberty…\' given.',
1802,
],
[
'Parameter #1 $strings of method Test\WeirdArrayBug::doFoo() expects array<string>|string, array given.',
1819,
],
[
'Parameter #1 $string of method Test\NonFalsyString::acceptsNonFalsyString() expects non-falsy-string, numeric-string given.',
1844,
Expand Down Expand Up @@ -810,6 +826,10 @@ public function testCallMethodsOnThisOnly(): void
'Call to an undefined method Test\CallAfterPropertyEmpty::doBar().',
1072,
],
[
'Parameter #1 $as of method Test\AssertInForeach::doBar() expects array<Test\AssertInForeach>, list<mixed> given.',
1177,
],
[
'Parameter #1 $i of method Test\SubtractedMixed::requireInt() expects int, mixed given.',
1277,
Expand All @@ -825,6 +845,14 @@ public function testCallMethodsOnThisOnly(): void
1285,
'Type int|string has already been eliminated from mixed.',
],
[
'Parameter #2 $y of method Test\NonEmptyArrayAcceptsBug::doBaz() expects array<stdClass>, array given.',
1332,
],
[
'Parameter #2 $y of method Test\NonEmptyArrayAcceptsBug::doLorem() expects iterable<stdClass>, array given.',
1333,
],
[
'Parameter #2 $b of method Test\ExpectsExceptionGenerics::expectsExceptionUpperBound() expects Exception, Throwable given.',
1378,
Expand Down Expand Up @@ -888,6 +916,10 @@ public function testCallMethodsOnThisOnly(): void
'Parameter #1 $code of method Test\\ValueOfParam::foo() expects \'John F. Kennedy…\'|\'La Guardia Airport\', \'Newark Liberty…\' given.',
1802,
],
[
'Parameter #1 $strings of method Test\WeirdArrayBug::doFoo() expects array<string>|string, array given.',
1819,
],
[
'Parameter #1 $string of method Test\NonFalsyString::acceptsNonFalsyString() expects non-falsy-string, numeric-string given.',
1844,
Expand Down Expand Up @@ -1654,7 +1686,12 @@ public static function dataImplicitMixed(): array
],
[
false,
[],
[
[
'Parameter #1 $cb of method CheckImplicitMixedMethodCall\CallableMixed::doBar2() expects callable(): int, Closure(): mixed given.',
139,
],
],
],
];
}
Expand Down Expand Up @@ -2857,7 +2894,7 @@ public function testNonEmptyArray(): void
[
'Parameter #1 $nonEmpty of method AcceptNonEmptyArray\Foo::requireNonEmpty() expects non-empty-array<int>, array<int> given.',
15,
'array<int> might be empty.',
'array<int|string, int> might be empty.',
],
[
'Parameter #1 $nonEmpty of method AcceptNonEmptyArray\Foo::requireNonEmpty() expects non-empty-array<int>, array{} given.',
Expand Down
26 changes: 24 additions & 2 deletions tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ public function testBug8071(): void
// there should be no errors
'Method Bug8071\Inheritance::inherit() should return array<TKey of (int|string), TValues of bool|float|int|string|null> but returns array<string>.',
17,
'Type string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.',
"• Type string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.\n• Type string is not always the same as TKey. It breaks the contract for some argument types, typically subtypes.\n• Type int is not always the same as TKey. It breaks the contract for some argument types, typically subtypes.",
],
]);
}
Expand Down Expand Up @@ -1047,7 +1047,7 @@ public function testWrongListTip(): void
[
'Method WrongListTip\Test3::doFoo() should return non-empty-list<WrongListTip\Foo> but returns array<WrongListTip\Bar>.',
67,
"• array<WrongListTip\Bar> might not be a list.\n• array<WrongListTip\Bar> might be empty.",
"• array<int|string, WrongListTip\Bar> might not be a list.\n• array<int|string, WrongListTip\Bar> might be empty.",
],
]);
}
Expand Down Expand Up @@ -1347,4 +1347,26 @@ public function testBug14553(): void
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-14553.php'], []);
}

public function testBug8681(): void
{
$this->analyse([__DIR__ . '/data/bug-8681.php'], [
[
'Method Bug8681\HelloWorld::test() should return array<string, string> but returns array.',
14,
],
[
'Method Bug8681\HelloWorld::testExplicitMixed() should return array<string, string> but returns array<mixed>.',
24,
],
[
'Method Bug8681\HelloWorld::testIterable() should return iterable<string, string> but returns iterable.',
34,
],
[
'Method Bug8681\HelloWorld::testNested() should return array<string, array<string, int>> but returns array<string, array>.',
44,
],
]);
}

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

namespace Bug8681;

class HelloWorld
{
/**
* @return array<string, string>
*/
public function test(): array
{
/** @var array $a */
$a = [];
return $a;
}

/**
* @return array<string, string>
*/
public function testExplicitMixed(): array
{
/** @var array<mixed, mixed> $a */
$a = [];
return $a;
}

/**
* @return iterable<string, string>
*/
public function testIterable(): iterable
{
/** @var iterable $a */
$a = [];
return $a;
}

/**
* @return array<string, array<string, int>>
*/
public function testNested(): array
{
/** @var array<string, array> $a */
$a = [];
return $a;
}
}
Loading
Loading