Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP 8.2 | Tokenizer, File, sniffs: account for new true type #3662

Closed
wants to merge 6 commits into from
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
3 changes: 3 additions & 0 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,7 @@ public function getMethodParameters($stackPtr)
case T_TYPE_UNION:
case T_TYPE_INTERSECTION:
case T_FALSE:
case T_TRUE:
case T_NULL:
// Part of a type hint or default value.
if ($defaultStart === null) {
Expand Down Expand Up @@ -1692,6 +1693,7 @@ public function getMethodProperties($stackPtr)
T_PARENT => T_PARENT,
T_STATIC => T_STATIC,
T_FALSE => T_FALSE,
T_TRUE => T_TRUE,
T_NULL => T_NULL,
T_NAMESPACE => T_NAMESPACE,
T_NS_SEPARATOR => T_NS_SEPARATOR,
Expand Down Expand Up @@ -1893,6 +1895,7 @@ public function getMemberProperties($stackPtr)
T_SELF => T_SELF,
T_PARENT => T_PARENT,
T_FALSE => T_FALSE,
T_TRUE => T_TRUE,
T_NULL => T_NULL,
T_NAMESPACE => T_NAMESPACE,
T_NS_SEPARATOR => T_NS_SEPARATOR,
Expand Down
1 change: 1 addition & 0 deletions src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class LowerCaseTypeSniff implements Sniff
'mixed' => true,
'static' => true,
'false' => true,
'true' => true,
'null' => true,
'never' => true,
];
Expand Down
2 changes: 2 additions & 0 deletions src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ function intersectionReturnTypes ($var): \Package\ClassName&\Package\Other_Class

$arrow = fn (int $a, string $b, bool $c, array $d, Foo\Bar $e) : int => $a * $b;
$arrow = fn (Int $a, String $b, BOOL $c, Array $d, Foo\Bar $e) : Float => $a * $b;

$cl = function (False $a, TRUE $b, Null $c): ?True {}
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ function intersectionReturnTypes ($var): \Package\ClassName&\Package\Other_Class

$arrow = fn (int $a, string $b, bool $c, array $d, Foo\Bar $e) : int => $a * $b;
$arrow = fn (int $a, string $b, bool $c, array $d, Foo\Bar $e) : float => $a * $b;

$cl = function (false $a, true $b, null $c): ?true {}
1 change: 1 addition & 0 deletions src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public function getErrorList()
82 => 2,
85 => 1,
94 => 5,
96 => 4,
];

}//end getErrorList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class NullableTypeDeclarationSniff implements Sniff
T_SELF => true,
T_PARENT => true,
T_STATIC => true,
T_NULL => true,
T_FALSE => true,
T_TRUE => true,
];


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ class testInstanceOf() {

// PHP 8.0: static return type.
function testStatic() : ? static {}

// PHP 8.2: nullable true/false.
function fooG(): ? true {}
function fooH(): ?
false {}

// Fatal error: null cannot be marked as nullable, but that's not the concern of this sniff.
function fooI(): ? null {}
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,10 @@ class testInstanceOf() {

// PHP 8.0: static return type.
function testStatic() : ?static {}

// PHP 8.2: nullable true/false.
function fooG(): ?true {}
function fooH(): ?false {}

// Fatal error: null cannot be marked as nullable, but that's not the concern of this sniff.
function fooI(): ?null {}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ protected function getErrorList()
58 => 2,
59 => 2,
87 => 1,
90 => 1,
91 => 1,
95 => 1,
];

}//end getErrorList()
Expand Down
1 change: 1 addition & 0 deletions src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -2803,6 +2803,7 @@ protected function processAdditional()
T_PARENT => T_PARENT,
T_STATIC => T_STATIC,
T_FALSE => T_FALSE,
T_TRUE => T_TRUE,
T_NULL => T_NULL,
T_NAMESPACE => T_NAMESPACE,
T_NS_SEPARATOR => T_NS_SEPARATOR,
Expand Down
21 changes: 18 additions & 3 deletions tests/Core/File/GetMemberPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,11 @@ $anon = class() {
public ?int|float $unionTypesNullable;

/* testPHP8PseudoTypeNull */
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
public null $pseudoTypeNull;

/* testPHP8PseudoTypeFalse */
// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
public false $pseudoTypeFalse;

/* testPHP8PseudoTypeFalseAndBool */
Expand Down Expand Up @@ -298,7 +298,22 @@ $anon = class() {
// Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method.
public int&string $illegalIntersectionType;

/* testPHP81NulltableIntersectionType */
/* testPHP81NullableIntersectionType */
// Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method.
public ?Foo&Bar $nullableIntersectionType;
};

$anon = class() {
/* testPHP82PseudoTypeTrue */
public true $pseudoTypeTrue;

/* testPHP82NullablePseudoTypeTrue */
static protected ?true $pseudoTypeNullableTrue;

/* testPHP82PseudoTypeTrueInUnion */
private int|string|true $pseudoTypeTrueInUnion;

/* testPHP82PseudoTypeFalseAndTrue */
// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method.
readonly true|FALSE $pseudoTypeFalseAndTrue;
};
51 changes: 50 additions & 1 deletion tests/Core/File/GetMemberPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ public function dataGetMemberProperties()
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'Foo&Bar',
'nullable_type' => false,
],
Expand All @@ -774,6 +775,7 @@ public function dataGetMemberProperties()
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'Foo&Bar&Baz',
'nullable_type' => false,
],
Expand All @@ -784,20 +786,67 @@ public function dataGetMemberProperties()
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'int&string',
'nullable_type' => false,
],
],
[
'/* testPHP81NulltableIntersectionType */',
'/* testPHP81NullableIntersectionType */',
[
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => '?Foo&Bar',
'nullable_type' => true,
],
],
[
'/* testPHP82PseudoTypeTrue */',
[
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'true',
'nullable_type' => false,
],
],
[
'/* testPHP82NullablePseudoTypeTrue */',
[
'scope' => 'protected',
'scope_specified' => true,
'is_static' => true,
'is_readonly' => false,
'type' => '?true',
'nullable_type' => true,
],
],
[
'/* testPHP82PseudoTypeTrueInUnion */',
[
'scope' => 'private',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'int|string|true',
'nullable_type' => false,
],
],
[
'/* testPHP82PseudoTypeFalseAndTrue */',
[
'scope' => 'public',
'scope_specified' => false,
'is_static' => false,
'is_readonly' => true,
'type' => 'true|FALSE',
'nullable_type' => false,
],
],

];

}//end dataGetMemberProperties()
Expand Down
11 changes: 9 additions & 2 deletions tests/Core/File/GetMethodParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var
$closure = function (?int|float $number) {};

/* testPHP8PseudoTypeNull */
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeNull(null $var = null) {}

/* testPHP8PseudoTypeFalse */
// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeFalse(false $var = false) {}

/* testPHP8PseudoTypeFalseAndBool */
Expand Down Expand Up @@ -162,3 +162,10 @@ $closure = function (string&int $numeric_string) {};
/* testPHP81NullableIntersectionTypes */
// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method.
$closure = function (?Foo&Bar $object) {};

/* testPHP82PseudoTypeTrue */
function pseudoTypeTrue(?true $var = true) {}

/* testPHP82PseudoTypeFalseAndTrue */
// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method.
function pseudoTypeFalseAndTrue(true|false $var = true) {}
48 changes: 48 additions & 0 deletions tests/Core/File/GetMethodParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,54 @@ public function testPHP81NullableIntersectionTypes()
}//end testPHP81NullableIntersectionTypes()


/**
* Verify recognition of PHP 8.2 stand-alone `true` type.
*
* @return void
*/
public function testPHP82PseudoTypeTrue()
{
$expected = [];
$expected[0] = [
'name' => '$var',
'content' => '?true $var = true',
'default' => 'true',
'has_attributes' => false,
'pass_by_reference' => false,
'variable_length' => false,
'type_hint' => '?true',
'nullable_type' => true,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeTrue()


/**
* Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true.
*
* @return void
*/
public function testPHP82PseudoTypeFalseAndTrue()
{
$expected = [];
$expected[0] = [
'name' => '$var',
'content' => 'true|false $var = true',
'default' => 'true',
'has_attributes' => false,
'pass_by_reference' => false,
'variable_length' => false,
'type_hint' => 'true|false',
'nullable_type' => false,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeFalseAndTrue()


/**
* Test helper.
*
Expand Down
11 changes: 9 additions & 2 deletions tests/Core/File/GetMethodPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterabl
$closure = function () use($a) :?int|float {};

/* testPHP8PseudoTypeNull */
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeNull(): null {}

/* testPHP8PseudoTypeFalse */
// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeFalse(): false {}

/* testPHP8PseudoTypeFalseAndBool */
Expand Down Expand Up @@ -150,3 +150,10 @@ $closure = function (): string&int {};
/* testPHP81NullableIntersectionTypes */
// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method.
$closure = function (): ?Foo&Bar {};

/* testPHP82PseudoTypeTrue */
function pseudoTypeTrue(): ?true {}

/* testPHP82PseudoTypeFalseAndTrue */
// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method.
function pseudoTypeFalseAndTrue(): true|false {}
46 changes: 46 additions & 0 deletions tests/Core/File/GetMethodPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,52 @@ public function testPHP81NullableIntersectionTypes()
}//end testPHP81NullableIntersectionTypes()


/**
* Verify recognition of PHP 8.2 stand-alone `true` type.
*
* @return void
*/
public function testPHP82PseudoTypeTrue()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '?true',
'nullable_return_type' => true,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeTrue()


/**
* Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true.
*
* @return void
*/
public function testPHP82PseudoTypeFalseAndTrue()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => 'true|false',
'nullable_return_type' => false,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeFalseAndTrue()


/**
* Test helper.
*
Expand Down
9 changes: 9 additions & 0 deletions tests/Core/Tokenizer/BitwiseOrTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ $obj->fn($something | $else);
/* testTypeUnionNonArrowFunctionDeclaration */
function &fn(int|false $something) {}

/* testTypeUnionPHP82TrueFirst */
function trueTypeParam(true|null $param) {}

/* testTypeUnionPHP82TrueMiddle */
function trueTypeReturn($param): array|true|null {}

/* testTypeUnionPHP82TrueLast */
$closure = function ($param): array|true {}

/* testLiveCoding */
// Intentional parse error. This has to be the last test in the file.
return function( type|
Loading