Skip to content

Commit

Permalink
Merge pull request #524 from PHPCSStandards/backcompat/bcfile-various…
Browse files Browse the repository at this point in the history
…-sync-add-support-for-true-type

PHP 8.2 | BCFile::get*() methods: sync with upstream / add support for true pseudotype
  • Loading branch information
jrfnl authored Dec 8, 2023
2 parents 5cd5676 + d1ddb2c commit 183a825
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 422 deletions.
1 change: 1 addition & 0 deletions PHPCSUtils/BackCompat/BCFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ public static function getMethodParameters(File $phpcsFile, $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
14 changes: 0 additions & 14 deletions PHPCSUtils/Utils/FunctionDeclarations.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ public static function getName(File $phpcsFile, $stackPtr)
* - Defensive coding against incorrect calls to this method.
* - More efficient checking whether a function has a body.
* - Support for PHP 8.0 identifier name tokens in return types, cross-version PHP & PHPCS.
* - Support for the PHP 8.2 `true` type.
* - The results of this function call are cached during a PHPCS run for faster response times.
*
* @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source.
Expand Down Expand Up @@ -248,12 +247,6 @@ public static function getProperties(File $phpcsFile, $stackPtr)
$hasBody = false;
$returnTypeTokens = Collections::returnTypeTokens();

/*
* BC PHPCS < 3.x.x: The union type separator is not (yet) retokenized correctly
* for union types containing the `true` type.
*/
$returnTypeTokens[\T_BITWISE_OR] = \T_BITWISE_OR;

$parenthesisCloser = null;
if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) {
$parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer'];
Expand Down Expand Up @@ -367,7 +360,6 @@ public static function getProperties(File $phpcsFile, $stackPtr)
* - More efficient and more stable looping of the default value.
* - Clearer exception message when a non-closure use token was passed to the function.
* - Support for PHP 8.0 identifier name tokens in parameter types, cross-version PHP & PHPCS.
* - Support for the PHP 8.2 `true` type.
* - The results of this function call are cached during a PHPCS run for faster response times.
*
* @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source.
Expand Down Expand Up @@ -447,12 +439,6 @@ public static function getParameters(File $phpcsFile, $stackPtr)

$parameterTypeTokens = Collections::parameterTypeTokens();

/*
* BC PHPCS < 3.x.x: The union type separator is not (yet) retokenized correctly
* for union types containing the `true` type.
*/
$parameterTypeTokens[\T_BITWISE_OR] = \T_BITWISE_OR;

for ($i = $paramStart; $i <= $closer; $i++) {
if (isset($parameterTypeTokens[$tokens[$i]['code']]) === true
/*
Expand Down
7 changes: 0 additions & 7 deletions PHPCSUtils/Utils/Variables.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ final class Variables
* other non-property variables passed to the method.
* - Defensive coding against incorrect calls to this method.
* - Support PHP 8.0 identifier name tokens in property types, cross-version PHP & PHPCS.
* - Support for the PHP 8.2 `true` type.
* - The results of this function call are cached during a PHPCS run for faster response times.
*
* @see \PHP_CodeSniffer\Files\File::getMemberProperties() Original source.
Expand Down Expand Up @@ -183,12 +182,6 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr)
$nullableType = false;
$propertyTypeTokens = Collections::propertyTypeTokens();

/*
* BC PHPCS < 3.x.x: The union type separator is not (yet) retokenized correctly
* for union types containing the `true` type.
*/
$propertyTypeTokens[\T_BITWISE_OR] = \T_BITWISE_OR;

if ($i < $stackPtr) {
// We've found a type.
for ($i; $i < $stackPtr; $i++) {
Expand Down
19 changes: 17 additions & 2 deletions Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,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 @@ -316,6 +316,21 @@ $anon = class() {
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;
};

class WhitespaceAndCommentsInTypes {
/* testUnionTypeWithWhitespaceAndComment */
public int | /*comment*/ string $hasWhitespaceAndComment;
Expand Down
54 changes: 53 additions & 1 deletion Tests/BackCompat/BCFile/GetMemberPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ public static function dataGetMemberProperties()
'is_static' => false,
'is_readonly' => false,
// Missing static, but that's OK as not an allowed syntax.
'type' => 'callable||void',
'type' => 'callable|void',
'type_token' => -6, // Offset from the T_VARIABLE token.
'type_end_token' => -2, // Offset from the T_VARIABLE token.
'nullable_type' => false,
Expand Down Expand Up @@ -1044,6 +1044,58 @@ public static function dataGetMemberProperties()
'nullable_type' => false,
],
],
'php8.2-pseudo-type-true' => [
'/* testPHP82PseudoTypeTrue */',
[
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'true',
'type_token' => -2, // Offset from the T_VARIABLE token.
'type_end_token' => -2, // Offset from the T_VARIABLE token.
'nullable_type' => false,
],
],
'php8.2-pseudo-type-true-nullable' => [
'/* testPHP82NullablePseudoTypeTrue */',
[
'scope' => 'protected',
'scope_specified' => true,
'is_static' => true,
'is_readonly' => false,
'type' => '?true',
'type_token' => -2, // Offset from the T_VARIABLE token.
'type_end_token' => -2, // Offset from the T_VARIABLE token.
'nullable_type' => true,
],
],
'php8.2-pseudo-type-true-in-union' => [
'/* testPHP82PseudoTypeTrueInUnion */',
[
'scope' => 'private',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'int|string|true',
'type_token' => -6, // Offset from the T_VARIABLE token.
'type_end_token' => -2, // Offset from the T_VARIABLE token.
'nullable_type' => false,
],
],
'php8.2-pseudo-type-invalid-true-false-union' => [
'/* testPHP82PseudoTypeFalseAndTrue */',
[
'scope' => 'public',
'scope_specified' => false,
'is_static' => false,
'is_readonly' => true,
'type' => 'true|FALSE',
'type_token' => -4, // Offset from the T_VARIABLE token.
'type_end_token' => -2, // Offset from the T_VARIABLE token.
'nullable_type' => false,
],
],
];
}

Expand Down
11 changes: 9 additions & 2 deletions Tests/BackCompat/BCFile/GetMethodParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,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 @@ -267,6 +267,13 @@ $closure = function (string&int $numeric_string) {};
// 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) {}

/* testPHP81NewInInitializers */
function newInInitializers(
TypeA $new = new TypeA(self::CONST_VALUE),
Expand Down
60 changes: 60 additions & 0 deletions Tests/BackCompat/BCFile/GetMethodParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2436,6 +2436,66 @@ public function testPHP81NullableIntersectionTypes()
$this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected);
}

/**
* Verify recognition of PHP 8.2 stand-alone `true` type.
*
* @return void
*/
public function testPHP82PseudoTypeTrue()
{
$expected = [];
$expected[0] = [
'token' => 7, // Offset from the T_FUNCTION token.
'name' => '$var',
'content' => '?true $var = true',
'default' => 'true',
'default_token' => 11, // Offset from the T_FUNCTION token.
'default_equal_token' => 9, // Offset from the T_FUNCTION token.
'has_attributes' => false,
'pass_by_reference' => false,
'reference_token' => false,
'variable_length' => false,
'variadic_token' => false,
'type_hint' => '?true',
'type_hint_token' => 5, // Offset from the T_FUNCTION token.
'type_hint_end_token' => 5, // Offset from the T_FUNCTION token.
'nullable_type' => true,
'comma_token' => false,
];

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

/**
* Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true.
*
* @return void
*/
public function testPHP82PseudoTypeFalseAndTrue()
{
$expected = [];
$expected[0] = [
'token' => 8, // Offset from the T_FUNCTION token.
'name' => '$var',
'content' => 'true|false $var = true',
'default' => 'true',
'default_token' => 12, // Offset from the T_FUNCTION token.
'default_equal_token' => 10, // Offset from the T_FUNCTION token.
'has_attributes' => false,
'pass_by_reference' => false,
'reference_token' => false,
'variable_length' => false,
'variadic_token' => false,
'type_hint' => 'true|false',
'type_hint_token' => 4, // Offset from the T_FUNCTION token.
'type_hint_end_token' => 6, // Offset from the T_FUNCTION token.
'nullable_type' => false,
'comma_token' => false,
];

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

/**
* Verify behaviour when the default value uses the "new" keyword, as is allowed per PHP 8.1.
*
Expand Down
11 changes: 9 additions & 2 deletions Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,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 @@ -158,6 +158,13 @@ $closure = function (): string&int {};
// 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 {}

/* testNotAFunction */
return true;

Expand Down
46 changes: 46 additions & 0 deletions Tests/BackCompat/BCFile/GetMethodPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,52 @@ public function testPHP81NullableIntersectionTypes()
$this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected);
}

/**
* Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability.
*
* @return void
*/
public function testPHP82PseudoTypeTrue()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '?true',
'return_type_token' => 8, // Offset from the T_FUNCTION token.
'return_type_end_token' => 8, // Offset from the T_FUNCTION token.
'nullable_return_type' => true,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

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

/**
* Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability.
*
* @return void
*/
public function testPHP82PseudoTypeFalseAndTrue()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => 'true|false',
'return_type_token' => 7, // Offset from the T_FUNCTION token.
'return_type_end_token' => 9, // Offset from the T_FUNCTION token.
'nullable_return_type' => false,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

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

/**
* Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0.
*
Expand Down
8 changes: 0 additions & 8 deletions Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc

This file was deleted.

Loading

0 comments on commit 183a825

Please sign in to comment.