2016-12-11 23:41:11 -05:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Tests;
|
|
|
|
|
|
|
|
use Psalm\Checker\FileChecker;
|
|
|
|
use Psalm\Context;
|
|
|
|
|
2017-04-24 23:45:02 -04:00
|
|
|
class AnnotationTest extends TestCase
|
2016-12-11 23:41:11 -05:00
|
|
|
{
|
2017-04-24 23:45:02 -04:00
|
|
|
use Traits\FileCheckerInvalidCodeParseTestTrait;
|
|
|
|
use Traits\FileCheckerValidCodeParseTestTrait;
|
2016-12-24 18:23:22 +00:00
|
|
|
|
2017-01-13 14:07:23 -05:00
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
2016-12-24 18:23:22 +00:00
|
|
|
public function testNopType()
|
|
|
|
{
|
2017-07-25 16:11:02 -04:00
|
|
|
$this->addFile(
|
|
|
|
'somefile.php',
|
|
|
|
'<?php
|
|
|
|
$a = "hello";
|
2016-12-24 18:23:22 +00:00
|
|
|
|
2017-07-25 16:11:02 -04:00
|
|
|
/** @var int $a */
|
|
|
|
'
|
|
|
|
);
|
2016-12-24 18:23:22 +00:00
|
|
|
|
2017-07-25 16:11:02 -04:00
|
|
|
$file_checker = new FileChecker('somefile.php', $this->project_checker);
|
2017-01-16 18:33:04 -05:00
|
|
|
$context = new Context();
|
2017-01-07 15:09:47 -05:00
|
|
|
$file_checker->visitAndAnalyzeMethods($context);
|
2017-05-26 20:05:57 -04:00
|
|
|
$this->assertSame('int', (string) $context->vars_in_scope['$a']);
|
2016-12-24 18:23:22 +00:00
|
|
|
}
|
2016-12-31 00:14:00 -05:00
|
|
|
|
2017-03-19 14:39:05 -04:00
|
|
|
/**
|
2017-04-24 23:45:02 -04:00
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function providerFileCheckerValidCodeParse()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'deprecatedMethod' => [
|
|
|
|
'<?php
|
|
|
|
class Foo {
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
|
|
|
public static function barBar() : void {
|
|
|
|
}
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'validDocblockReturn' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function fooFoo() : string {
|
|
|
|
return "boop";
|
|
|
|
}
|
2017-05-04 18:35:05 -04:00
|
|
|
|
2017-04-24 23:45:02 -04:00
|
|
|
/**
|
|
|
|
* @return array<int, string>
|
|
|
|
*/
|
|
|
|
function foo2() : array {
|
|
|
|
return ["hello"];
|
|
|
|
}
|
2017-05-04 18:35:05 -04:00
|
|
|
|
2017-04-24 23:45:02 -04:00
|
|
|
/**
|
|
|
|
* @return array<int, string>
|
|
|
|
*/
|
|
|
|
function foo3() : array {
|
|
|
|
return ["hello"];
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'reassertWithIs' => [
|
|
|
|
'<?php
|
|
|
|
/** @param array $a */
|
|
|
|
function foo($a) : void {
|
|
|
|
if (is_array($a)) {
|
|
|
|
// do something
|
|
|
|
}
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'checkArrayWithIs' => [
|
|
|
|
'<?php
|
|
|
|
/** @param mixed $b */
|
|
|
|
function foo($b) : void {
|
|
|
|
/** @var array */
|
|
|
|
$a = (array)$b;
|
|
|
|
if (is_array($a)) {
|
|
|
|
// do something
|
|
|
|
}
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'checkArrayWithIsInsideLoop' => [
|
|
|
|
'<?php
|
|
|
|
/** @param array<mixed, array<mixed, mixed>> $data */
|
|
|
|
function foo($data) : void {
|
|
|
|
foreach ($data as $key => $val) {
|
|
|
|
if (!\is_array($data)) {
|
|
|
|
$data = [$key => null];
|
|
|
|
} else {
|
|
|
|
$data[$key] = !empty($val);
|
|
|
|
}
|
|
|
|
}
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'goodDocblock' => [
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
/**
|
|
|
|
* @param A $a
|
|
|
|
* @param bool $b
|
|
|
|
*/
|
|
|
|
public function g(A $a, $b) : void {
|
|
|
|
}
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'goodDocblockInNamespace' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
2017-05-04 18:35:05 -04:00
|
|
|
|
2017-04-24 23:45:02 -04:00
|
|
|
class A {
|
|
|
|
/**
|
|
|
|
* @param \Foo\A $a
|
|
|
|
* @param bool $b
|
|
|
|
*/
|
|
|
|
public function g(A $a, $b) : void {
|
|
|
|
}
|
2017-05-26 20:05:57 -04:00
|
|
|
}',
|
2017-05-04 18:35:05 -04:00
|
|
|
],
|
|
|
|
'propertyDocblock' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @property string $foo
|
|
|
|
*/
|
|
|
|
class A {
|
2017-09-02 11:18:56 -04:00
|
|
|
/** @param string $name */
|
|
|
|
public function __get($name) : ?string {
|
|
|
|
if ($name === "foo") {
|
|
|
|
return "hello";
|
|
|
|
}
|
|
|
|
}
|
2017-05-04 18:35:05 -04:00
|
|
|
|
2017-09-02 11:18:56 -04:00
|
|
|
/**
|
|
|
|
* @param string $name
|
|
|
|
* @param mixed $value
|
|
|
|
*/
|
|
|
|
public function __set($name, $value) : void {
|
|
|
|
}
|
2017-05-04 18:35:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
$a = new A();
|
2017-11-16 20:47:58 -05:00
|
|
|
$a->foo = "hello";
|
|
|
|
$a->bar = "hello"; // not a property',
|
2017-05-04 18:35:05 -04:00
|
|
|
],
|
2017-05-10 12:36:11 -04:00
|
|
|
'ignoreNullableReturn' => [
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
/** @var int */
|
|
|
|
public $bar = 5;
|
|
|
|
public function foo() : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return ?A
|
|
|
|
* @psalm-ignore-nullable-return
|
|
|
|
*/
|
|
|
|
function makeA() {
|
|
|
|
return rand(0, 1) ? new A() : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function takeA(A $a) : void { }
|
|
|
|
|
|
|
|
$a = makeA();
|
|
|
|
$a->foo();
|
|
|
|
$a->bar = 7;
|
2017-05-26 20:05:57 -04:00
|
|
|
takeA($a);',
|
2017-05-10 12:36:11 -04:00
|
|
|
],
|
2017-06-13 14:00:41 -04:00
|
|
|
'invalidDocblockParamSuppress' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @param int $bar
|
|
|
|
* @psalm-suppress InvalidDocblock
|
|
|
|
*/
|
|
|
|
function fooFoo(array $bar) : void {
|
|
|
|
}',
|
|
|
|
],
|
2017-07-25 16:11:02 -04:00
|
|
|
'differentDocblockParamClassSuppress' => [
|
|
|
|
'<?php
|
|
|
|
class A {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param B $bar
|
|
|
|
* @psalm-suppress InvalidDocblock
|
|
|
|
*/
|
|
|
|
function fooFoo(A $bar) : void {
|
|
|
|
}',
|
|
|
|
],
|
|
|
|
'varDocblock' => [
|
|
|
|
'<?php
|
|
|
|
/** @var array<Exception> */
|
|
|
|
$a = [];
|
|
|
|
|
|
|
|
$a[0]->getMessage();',
|
|
|
|
],
|
2017-09-02 11:18:56 -04:00
|
|
|
'mixedDocblockParamTypeDefinedInParent' => [
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
/** @param mixed $a */
|
|
|
|
public function foo($a) : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class B extends A {
|
|
|
|
public function foo($a) : void {}
|
|
|
|
}',
|
|
|
|
],
|
|
|
|
'intDocblockParamTypeDefinedInParent' => [
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
/** @param int $a */
|
|
|
|
public function foo($a) : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class B extends A {
|
|
|
|
public function foo($a) : void {}
|
|
|
|
}',
|
|
|
|
],
|
2017-10-07 10:22:52 -04:00
|
|
|
'varSelf' => [
|
|
|
|
'<?php
|
|
|
|
class A
|
|
|
|
{
|
|
|
|
public function foo() : void {}
|
|
|
|
|
|
|
|
public function getMeAgain() : void {
|
|
|
|
/** @var self */
|
|
|
|
$me = $this;
|
|
|
|
$me->foo();
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
],
|
2017-11-02 21:45:17 -04:00
|
|
|
'psalmVar' => [
|
|
|
|
'<?php
|
|
|
|
class A
|
|
|
|
{
|
|
|
|
/** @psalm-var array<int, string> */
|
|
|
|
public $foo = [];
|
|
|
|
|
|
|
|
public function updateFoo() : void {
|
|
|
|
$this->foo[5] = "hello";
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
],
|
|
|
|
'psalmParam' => [
|
|
|
|
'<?php
|
|
|
|
function takesInt(int $a) : void {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @psalm-param array<int, string> $a
|
|
|
|
* @param string[] $a
|
|
|
|
*/
|
|
|
|
function foo(array $a) : void {
|
|
|
|
foreach ($a as $key => $value) {
|
|
|
|
takesInt($key);
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
],
|
2017-04-24 23:45:02 -04:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function providerFileCheckerInvalidCodeParse()
|
|
|
|
{
|
|
|
|
return [
|
2017-05-24 21:11:18 -04:00
|
|
|
'invalidReturn' => [
|
|
|
|
'<?php
|
|
|
|
interface I {
|
|
|
|
/**
|
|
|
|
* @return $thus
|
|
|
|
*/
|
|
|
|
public static function barBar();
|
|
|
|
}',
|
2017-11-14 21:43:31 -05:00
|
|
|
'error_message' => 'MissingDocblockType',
|
2017-05-24 21:11:18 -04:00
|
|
|
],
|
2017-07-09 20:32:35 -04:00
|
|
|
'invalidReturnClass' => [
|
|
|
|
'<?php
|
|
|
|
interface I {
|
|
|
|
/**
|
|
|
|
* @return 1
|
|
|
|
*/
|
|
|
|
public static function barBar();
|
|
|
|
}',
|
|
|
|
'error_message' => 'InvalidDocblock',
|
|
|
|
],
|
|
|
|
'invalidReturnClassWithComma' => [
|
|
|
|
'<?php
|
|
|
|
interface I {
|
|
|
|
/**
|
|
|
|
* @return 1,
|
|
|
|
*/
|
|
|
|
public static function barBar();
|
|
|
|
}',
|
|
|
|
'error_message' => 'InvalidDocblock',
|
|
|
|
],
|
|
|
|
'returnClassWithComma' => [
|
|
|
|
'<?php
|
|
|
|
interface I {
|
|
|
|
/**
|
|
|
|
* @return a,
|
|
|
|
*/
|
|
|
|
public static function barBar();
|
|
|
|
}',
|
|
|
|
'error_message' => 'InvalidDocblock',
|
|
|
|
],
|
2017-04-24 23:45:02 -04:00
|
|
|
'deprecatedMethodWithCall' => [
|
|
|
|
'<?php
|
|
|
|
class Foo {
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
|
|
|
public static function barBar() : void {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Foo::barBar();',
|
2017-05-26 20:05:57 -04:00
|
|
|
'error_message' => 'DeprecatedMethod',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
2017-05-25 00:34:39 -04:00
|
|
|
'deprecatedClassWithStaticCall' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
|
|
|
class Foo {
|
|
|
|
public static function barBar() : void {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Foo::barBar();',
|
2017-05-26 20:05:57 -04:00
|
|
|
'error_message' => 'DeprecatedClass',
|
2017-05-25 00:34:39 -04:00
|
|
|
],
|
|
|
|
'deprecatedClassWithNew' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
|
|
|
class Foo { }
|
|
|
|
|
|
|
|
$a = new Foo();',
|
2017-05-26 20:05:57 -04:00
|
|
|
'error_message' => 'DeprecatedClass',
|
2017-05-25 00:34:39 -04:00
|
|
|
],
|
2017-05-25 01:32:34 -04:00
|
|
|
'deprecatedPropertyGet' => [
|
|
|
|
'<?php
|
|
|
|
class A{
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
* @var ?int
|
|
|
|
*/
|
|
|
|
public $foo;
|
|
|
|
}
|
|
|
|
echo (new A)->foo;',
|
2017-05-26 20:05:57 -04:00
|
|
|
'error_message' => 'DeprecatedProperty',
|
2017-05-25 01:32:34 -04:00
|
|
|
],
|
|
|
|
'deprecatedPropertySet' => [
|
|
|
|
'<?php
|
|
|
|
class A{
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
* @var ?int
|
|
|
|
*/
|
|
|
|
public $foo;
|
|
|
|
}
|
|
|
|
$a = new A;
|
|
|
|
$a->foo = 5;',
|
2017-05-26 20:05:57 -04:00
|
|
|
'error_message' => 'DeprecatedProperty',
|
2017-05-25 01:32:34 -04:00
|
|
|
],
|
2017-04-24 23:45:02 -04:00
|
|
|
'missingParamType' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
2017-07-25 16:11:02 -04:00
|
|
|
* @param string $bar
|
2017-04-24 23:45:02 -04:00
|
|
|
*/
|
|
|
|
function fooBar() : void {
|
2017-07-25 16:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fooBar("hello");',
|
|
|
|
'error_message' => 'TooManyArguments',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'missingParamVar' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @param string
|
|
|
|
*/
|
|
|
|
function fooBar() : void {
|
|
|
|
}',
|
2017-07-26 21:30:01 -04:00
|
|
|
'error_message' => 'InvalidDocblock - src/somefile.php:5 - Badly-formatted @param',
|
2017-04-24 23:45:02 -04:00
|
|
|
],
|
|
|
|
'invalidDocblockReturn' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
2017-07-25 16:11:02 -04:00
|
|
|
function fooFoo() : int {
|
|
|
|
return 5;
|
2017-04-24 23:45:02 -04:00
|
|
|
}',
|
2017-05-26 20:05:57 -04:00
|
|
|
'error_message' => 'InvalidDocblock',
|
2017-05-04 18:35:05 -04:00
|
|
|
],
|
|
|
|
'propertyDocblockInvalidAssignment' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @property string $foo
|
|
|
|
*/
|
|
|
|
class A {
|
2017-11-03 12:27:01 -04:00
|
|
|
public function __get(string $name) : ?string {
|
2017-05-04 18:35:05 -04:00
|
|
|
if ($name === "foo") {
|
|
|
|
return "hello";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-03 12:27:01 -04:00
|
|
|
/** @param mixed $value */
|
|
|
|
public function __set(string $name, $value) : void {
|
2017-05-04 18:35:05 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$a = new A();
|
|
|
|
$a->foo = 5;',
|
|
|
|
'error_message' => 'InvalidPropertyAssignment',
|
|
|
|
],
|
2017-11-16 20:47:58 -05:00
|
|
|
'propertySealedDocblockUndefinedPropertyAssignment' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @property string $foo
|
|
|
|
* @psalm-seal-properties
|
|
|
|
*/
|
|
|
|
class A {
|
|
|
|
public function __get(string $name) : ?string {
|
|
|
|
if ($name === "foo") {
|
|
|
|
return "hello";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @param mixed $value */
|
|
|
|
public function __set(string $name, $value) : void {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$a = new A();
|
|
|
|
$a->bar = 5;',
|
|
|
|
'error_message' => 'UndefinedPropertyAssignment',
|
|
|
|
],
|
|
|
|
'propertySealedDocblockUndefinedPropertyFetch' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @property string $foo
|
|
|
|
* @psalm-seal-properties
|
|
|
|
*/
|
|
|
|
class A {
|
|
|
|
public function __get(string $name) : ?string {
|
|
|
|
if ($name === "foo") {
|
|
|
|
return "hello";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @param mixed $value */
|
|
|
|
public function __set(string $name, $value) : void {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$a = new A();
|
|
|
|
echo $a->bar;',
|
|
|
|
'error_message' => 'UndefinedPropertyFetch',
|
|
|
|
],
|
2017-09-02 18:15:52 -04:00
|
|
|
'noStringParamType' => [
|
2017-09-02 11:18:56 -04:00
|
|
|
'<?php
|
|
|
|
function fooFoo($a) : void {
|
2017-09-02 18:15:52 -04:00
|
|
|
echo substr($a, 4, 2);
|
2017-09-02 11:18:56 -04:00
|
|
|
}',
|
2017-09-02 18:15:52 -04:00
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:2 - Parameter $a has no provided type,'
|
|
|
|
. ' should be string',
|
|
|
|
'error_levels' => ['MixedArgument'],
|
|
|
|
],
|
2017-09-02 19:23:00 -04:00
|
|
|
'noParamTypeButConcat' => [
|
|
|
|
'<?php
|
|
|
|
function fooFoo($a) : void {
|
|
|
|
echo $a . "foo";
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:2 - Parameter $a has no provided type,'
|
|
|
|
. ' should be string',
|
|
|
|
'error_levels' => ['MixedOperand'],
|
|
|
|
],
|
2017-09-06 21:44:26 -04:00
|
|
|
'noParamTypeButAddition' => [
|
|
|
|
'<?php
|
|
|
|
function fooFoo($a) : void {
|
|
|
|
echo $a + 5;
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:2 - Parameter $a has no provided type,'
|
|
|
|
. ' should be int|float',
|
|
|
|
'error_levels' => ['MixedOperand', 'MixedArgument'],
|
|
|
|
],
|
|
|
|
'noParamTypeButDivision' => [
|
|
|
|
'<?php
|
|
|
|
function fooFoo($a) : void {
|
|
|
|
echo $a / 5;
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:2 - Parameter $a has no provided type,'
|
|
|
|
. ' should be int|float',
|
|
|
|
'error_levels' => ['MixedOperand', 'MixedArgument'],
|
|
|
|
],
|
2017-09-02 19:48:59 -04:00
|
|
|
'noParamTypeButTemplatedString' => [
|
|
|
|
'<?php
|
|
|
|
function fooFoo($a) : void {
|
|
|
|
echo "$a";
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:2 - Parameter $a has no provided type,'
|
|
|
|
. ' should be string',
|
|
|
|
'error_levels' => ['MixedOperand'],
|
|
|
|
],
|
2017-09-02 18:15:52 -04:00
|
|
|
'noStringIntParamType' => [
|
|
|
|
'<?php
|
|
|
|
function fooFoo($a) : void {
|
|
|
|
if (is_string($a)) {
|
|
|
|
echo substr($a, 4, 2);
|
|
|
|
} else {
|
|
|
|
echo substr("hello", $a, 2);
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:2 - Parameter $a has no provided type,'
|
|
|
|
. ' should be int|string',
|
|
|
|
'error_levels' => ['MixedArgument'],
|
2017-09-02 11:18:56 -04:00
|
|
|
],
|
|
|
|
'intParamTypeDefinedInParent' => [
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
public function foo(int $a) : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class B extends A {
|
|
|
|
public function foo($a) : void {}
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam',
|
|
|
|
'error_levels' => ['MethodSignatureMismatch'],
|
|
|
|
],
|
2017-09-02 18:15:52 -04:00
|
|
|
'alreadyHasCheck' => [
|
|
|
|
'<?php
|
|
|
|
function takesString(string $s) : void {}
|
|
|
|
|
|
|
|
function shouldTakeString($s) : void {
|
|
|
|
if (is_string($s)) takesString($s);
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:4 - Parameter $s has no provided type,'
|
|
|
|
. ' could not infer',
|
|
|
|
'error_levels' => ['MixedArgument'],
|
|
|
|
],
|
|
|
|
'isSetBeforeInferrence' => [
|
|
|
|
'input' => '<?php
|
|
|
|
function takesString(string $s) : void {}
|
|
|
|
|
|
|
|
/** @return mixed */
|
|
|
|
function returnsMixed() {}
|
|
|
|
|
|
|
|
function shouldTakeString($s) : void {
|
|
|
|
$s = returnsMixed();
|
|
|
|
takesString($s);
|
|
|
|
}',
|
|
|
|
'error_message' => 'UntypedParam - src/somefile.php:7 - Parameter $s has no provided type,'
|
|
|
|
. ' could not infer',
|
|
|
|
'error_levels' => ['MixedArgument', 'InvalidReturnType', 'MixedAssignment'],
|
|
|
|
],
|
2017-11-02 21:45:17 -04:00
|
|
|
'psalmInvalidVar' => [
|
|
|
|
'<?php
|
|
|
|
class A
|
|
|
|
{
|
|
|
|
/** @psalm-var array<int, string> */
|
|
|
|
public $foo = [];
|
|
|
|
|
|
|
|
public function updateFoo() : void {
|
|
|
|
$this->foo["boof"] = "hello";
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'error_message' => 'InvalidPropertyAssignment',
|
|
|
|
],
|
2017-11-14 21:43:31 -05:00
|
|
|
'incorrectDocblockOrder' => [
|
|
|
|
'<?php
|
|
|
|
class MyClass {
|
|
|
|
/**
|
|
|
|
* Comment
|
|
|
|
* @var $fooPropTypo string
|
|
|
|
*/
|
|
|
|
public $fooProp = "/tmp/file.txt";
|
|
|
|
}',
|
|
|
|
'error_message' => 'MissingDocblockType',
|
|
|
|
],
|
|
|
|
'badlyFormattedVar' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
function returns_strings() {
|
|
|
|
/** @var array(string) $result */
|
|
|
|
$result = ["example"];
|
|
|
|
return $result;
|
|
|
|
}',
|
|
|
|
'error_message' => 'InvalidDocblock',
|
|
|
|
],
|
|
|
|
'badlyWrittenVar' => [
|
|
|
|
'<?php
|
|
|
|
/** @param mixed $x */
|
|
|
|
function myvalue($x) : void {
|
|
|
|
/** @var $myVar MyNS\OtherClass */
|
|
|
|
$myVar = $x->conn()->method();
|
|
|
|
$myVar->otherMethod();
|
|
|
|
}',
|
|
|
|
'error_message' => 'MissingDocblockType',
|
|
|
|
],
|
2017-04-24 23:45:02 -04:00
|
|
|
];
|
2016-12-31 00:14:00 -05:00
|
|
|
}
|
2016-12-11 23:41:11 -05:00
|
|
|
}
|