1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Fix errors in doctrine/dbal

This commit is contained in:
Matthew Brown 2018-12-20 01:06:43 -05:00
parent 72c50be4b0
commit c3a1e77a53
3 changed files with 237 additions and 3 deletions

View File

@ -152,6 +152,7 @@ class ArrayFetchAnalyzer
if ($context->inside_isset
&& $stmt->dim
&& isset($stmt->dim->inferredType)
&& $stmt->var->inferredType->hasArray()
&& ($stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch
|| $stmt->var instanceof PhpParser\Node\Expr\ConstFetch)
) {
@ -649,9 +650,7 @@ class ArrayFetchAnalyzer
)) {
$expected_offset_types[] = $valid_offset_type->getId();
if (!$inside_isset) {
$array_access_type = Type::getMixed();
}
} else {
$has_valid_offset = true;

View File

@ -487,6 +487,24 @@ class IssetTest extends TestCase
'assertions' => [],
'error_levels' => ['MixedAssignment'],
],
'noCrashAfterIsset' => [
'<?php
/**
* @param string[] $columns
* @param mixed[] $options
*/
function foo(array $columns, array $options) : void {
$arr = $options["b"];
foreach ($arr as $a) {
if (isset($columns[$a]["c"])) {
return;
}
}
}',
'assertions' => [],
'error_levels' => ['MixedAssignment', 'MixedArrayOffset', 'InvalidArrayOffset'],
],
];
}

View File

@ -0,0 +1,217 @@
<?php
namespace Psalm\Tests;
use Psalm\Config;
use Psalm\Context;
class TypeAnnotationTest extends TestCase
{
use Traits\InvalidCodeAnalysisTestTrait;
use Traits\ValidCodeAnalysisTestTrait;
/**
* @return array
*/
public function providerValidCodeParse()
{
return [
'typeAliasBeforeClass' => [
'<?php
/**
* @psalm-type CoolType = A|B|null
*/
class A {}
class B {}
/** @return CoolType */
function foo() {
if (rand(0, 1)) {
return new A();
}
if (rand(0, 1)) {
return new B();
}
return null;
}
/** @param CoolType $a **/
function bar ($a) : void { }
bar(foo());'
],
'typeAliasBeforeFunction' => [
'<?php
/**
* @psalm-type A_OR_B = A|B
* @psalm-type CoolType = A_OR_B|null
* @return CoolType
*/
function foo() {
if (rand(0, 1)) {
return new A();
}
if (rand(0, 1)) {
return new B();
}
return null;
}
class A {}
class B {}
/** @param CoolType $a **/
function bar ($a) : void { }
bar(foo());'
],
'typeAliasInSeparateBlockBeforeFunction' => [
'<?php
/**
* @psalm-type CoolType = A|B|null
*/
/**
* @return CoolType
*/
function foo() {
if (rand(0, 1)) {
return new A();
}
if (rand(0, 1)) {
return new B();
}
return null;
}
class A {}
class B {}
/** @param CoolType $a **/
function bar ($a) : void { }
bar(foo());'
],
'almostFreeStandingTypeAlias' => [
'<?php
/**
* @psalm-type CoolType = A|B|null
*/
// this breaks up the line
class A {}
class B {}
/** @return CoolType */
function foo() {
if (rand(0, 1)) {
return new A();
}
if (rand(0, 1)) {
return new B();
}
return null;
}
/** @param CoolType $a **/
function bar ($a) : void { }
bar(foo());'
],
'typeAliasUsedTwice' => [
'<?php
/** @psalm-type TA = array<int, string> */
class Bar {
public function foo() : void {
$bar =
/** @return TA */
function() {
return ["hello"];
};
/** @var array<int, TA> */
$bat = [$bar(), $bar()];
foreach ($bat as $b) {
echo $b[0];
}
}
}
/**
* @psalm-type _A=array{elt:int}
* @param _A $p
* @return _A
*/
function f($p) {
/** @var _A */
$r = $p;
return $r;
}',
],
'namespacedType' => [
'<?php
namespace Foo {
class A {
/**
* @psalm-type self::TBaz = A|\Bar\B
*/
public function foo() : void {}
}
}
namespace Bar {
class B {
/**
* @param \Foo\A::TBaz $a
*/
public function tender($a) : void {
$a->foo();
}
public function foo() : void {}
}
}'
],
];
}
/**
* @return array
*/
public function providerInvalidCodeParse()
{
return [
'invalidTypeAlias' => [
'<?php
/**
* @psalm-type CoolType = A|B>
*/
class A {}',
'error_message' => 'InvalidDocblock',
],
'typeAliasInObjectLike' => [
'<?php
/**
* @psalm-type aType null|"a"|"b"|"c"|"d"
*/
/** @psalm-return array{0:bool,1:aType} */
function f(): array {
return [(bool)rand(0,1), rand(0,1) ? "z" : null];
}',
'error_message' => 'InvalidReturnStatement',
],
];
}
}