Skip to content

Commit

Permalink
Merge pull request #208 from PHPCSStandards/php-8.0/collections-retur…
Browse files Browse the repository at this point in the history
…ntypetokens-support-identifier-name-tokens

Collections::returnTypeTokens[BC](): support the PHP 8 identifier name tokens
  • Loading branch information
jrfnl committed Sep 13, 2020
2 parents 2786537 + 7242ea5 commit 85f43a9
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 15 deletions.
27 changes: 15 additions & 12 deletions PHPCSUtils/Tokens/Collections.php
Expand Up @@ -907,24 +907,26 @@ public static function propertyTypeTokensBC()
*
* @since 1.0.0-alpha4 This method replaces the {@see Collections::$returnTypeTokens} property.
* @since 1.0.0-alpha4 Added support for PHP 8.0 union types.
* @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens.
*
* @return array <int|string> => <int|string>
*/
public static function returnTypeTokens()
{
return [
\T_STRING => \T_STRING,
\T_CALLABLE => \T_CALLABLE,
\T_SELF => \T_SELF,
\T_PARENT => \T_PARENT,
\T_STATIC => \T_STATIC,
\T_FALSE => \T_FALSE, // Union types only.
\T_NULL => \T_NULL, // Union types only.
\T_ARRAY => \T_ARRAY, // Arrow functions PHPCS < 3.5.4 + union types.
\T_NAMESPACE => \T_NAMESPACE,
\T_NS_SEPARATOR => \T_NS_SEPARATOR,
\T_BITWISE_OR => \T_BITWISE_OR, // Union types.
$tokens = [
\T_CALLABLE => \T_CALLABLE,
\T_SELF => \T_SELF,
\T_PARENT => \T_PARENT,
\T_STATIC => \T_STATIC,
\T_FALSE => \T_FALSE, // Union types only.
\T_NULL => \T_NULL, // Union types only.
\T_ARRAY => \T_ARRAY, // Arrow functions PHPCS < 3.5.4 + union types.
\T_BITWISE_OR => \T_BITWISE_OR, // Union types.
];

$tokens += self::namespacedNameTokens();

return $tokens;
}

/**
Expand All @@ -946,6 +948,7 @@ public static function returnTypeTokens()
*
* @since 1.0.0-alpha3
* @since 1.0.0-alpha4 Added support for PHP 8.0 union types.
* @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens.
*
* @return array <int|string> => <int|string>
*/
Expand Down
2 changes: 2 additions & 0 deletions PHPCSUtils/Utils/FunctionDeclarations.php
Expand Up @@ -172,6 +172,7 @@ public static function getName(File $phpcsFile, $stackPtr)
* `T_STRING` tokens and examine them to check if these are arrow functions.
* - Support for PHP 8.0 union types.
* - Support for namespace operator in type declarations.
* - Support for PHP 8.0 identifier name tokens in return types, cross-version PHP & PHPCS.
*
* @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source.
* @see \PHPCSUtils\BackCompat\BCFile::getMethodProperties() Cross-version compatible version of the original.
Expand Down Expand Up @@ -700,6 +701,7 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr)
* @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Related function.
*
* @since 1.0.0
* @since 1.0.0-alpha4 Handling of PHP 8.0 identifier name tokens in return types, cross-version PHP & PHPCS.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
* @param int $stackPtr The token to retrieve the openers/closers for.
Expand Down
6 changes: 6 additions & 0 deletions Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc
Expand Up @@ -44,6 +44,12 @@ class MyClass {
function myFunction(): \MyNamespace /** comment *\/ comment */
\MyClass /* comment */
\Foo {}

/* testReturnUnqualifiedName */
private function myFunction(): ?MyClass {}

/* testReturnPartiallyQualifiedName */
function myFunction(): Sub\Level\MyClass {}
}

abstract class MyClass
Expand Down
44 changes: 44 additions & 0 deletions Tests/BackCompat/BCFile/GetMethodPropertiesTest.php
Expand Up @@ -343,6 +343,50 @@ public function testReturnMultilineNamespace()
$this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected);
}

/**
* Test a method with an unqualified named return type.
*
* @return void
*/
public function testReturnUnqualifiedName()
{
$expected = [
'scope' => 'private',
'scope_specified' => true,
'return_type' => '?MyClass',
'return_type_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);
}

/**
* Test a method with a partially qualified namespaced return type.
*
* @return void
*/
public function testReturnPartiallyQualifiedName()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => 'Sub\Level\MyClass',
'return_type_token' => 7, // 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 a basic abstract method.
*
Expand Down
12 changes: 9 additions & 3 deletions Tests/Tokens/Collections/ReturnTypeTokensTest.php
Expand Up @@ -33,19 +33,25 @@ class ReturnTypeTokensTest extends TestCase
public function testReturnTypeTokens()
{
$expected = [
\T_STRING => \T_STRING,
\T_CALLABLE => \T_CALLABLE,
\T_SELF => \T_SELF,
\T_PARENT => \T_PARENT,
\T_STATIC => \T_STATIC,
\T_FALSE => \T_FALSE,
\T_NULL => \T_NULL,
\T_ARRAY => \T_ARRAY,
\T_NAMESPACE => \T_NAMESPACE,
\T_NS_SEPARATOR => \T_NS_SEPARATOR,
\T_BITWISE_OR => \T_BITWISE_OR,
\T_NS_SEPARATOR => \T_NS_SEPARATOR,
\T_NAMESPACE => \T_NAMESPACE,
\T_STRING => \T_STRING,
];

if (\version_compare(\PHP_VERSION_ID, '80000', '>=') === true) {
$expected[\T_NAME_QUALIFIED] = \T_NAME_QUALIFIED;
$expected[\T_NAME_FULLY_QUALIFIED] = \T_NAME_FULLY_QUALIFIED;
$expected[\T_NAME_RELATIVE] = \T_NAME_RELATIVE;
}

$this->assertSame($expected, Collections::returnTypeTokens());
}
}
3 changes: 3 additions & 0 deletions Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc
Expand Up @@ -61,6 +61,9 @@ $a = fn($x) => yield 'k' => $x;
/* testReturnTypeNamespacedClass */
$fn = fn($x) : ?\My\NS\ClassName => $x;

/* testReturnTypePartiallyQualifiedClass */
$fn = fn($x) : ?NS\ClassName => $x;

/* testReturnTypeNullableFQNClass */
$a = fn(?\DateTime $x) : ?\DateTime => $x;

Expand Down
12 changes: 12 additions & 0 deletions Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php
Expand Up @@ -352,6 +352,18 @@ public function dataArrowFunction()
],
],
],
'arrow-function-with-return-type-nullable-partially-qualified-class' => [
'/* testReturnTypePartiallyQualifiedClass */',
[
'is' => true,
'get' => [
'parenthesis_opener' => 1,
'parenthesis_closer' => 3,
'scope_opener' => ($php8Names === true) ? 10 : 12,
'scope_closer' => ($php8Names === true) ? 13 : 15,
],
],
],
'arrow-function-with-fqn-class' => [
'/* testReturnTypeNullableFQNClass */',
[
Expand Down
24 changes: 24 additions & 0 deletions Tests/Utils/Operators/IsTypeUnionTest.inc
Expand Up @@ -27,6 +27,15 @@ class TypeUnion
/* testTypeUnionPropertyMulti3 */
| null $arrayOrFalse;

/* testTypeUnionPropertyNamespaceRelative */
public namespace\Sub\NameA|namespace\Sub\NameB $namespaceRelative;

/* testTypeUnionPropertyPartiallyQualified */
public Partially\Qualified\NameA|Partially\Qualified\NameB $partiallyQual;

/* testTypeUnionPropertyFullyQualified */
public \Fully\Qualified\NameA|\Fully\Qualified\NameB $fullyQual;

public function paramTypes(
/* testTypeUnionParam1 */
int|float $paramA /* testBitwiseOrParamDefaultValue */ = CONSTANT_A | CONSTANT_B,
Expand All @@ -38,6 +47,15 @@ class TypeUnion
return (($a1 ^ $b1) |($a2 ^ $b2)) + $c;
}

public function identifierNames(
/* testTypeUnionParamNamespaceRelative */
namespace\Sub\NameA|namespace\Sub\NameB $paramA,
/* testTypeUnionParamPartiallyQualified */
Partially\Qualified\NameA|Partially\Qualified\NameB $paramB,
/* testTypeUnionParamFullyQualified */
\Fully\Qualified\NameA|\Fully\Qualified\NameB $paramC,
) {}

/* testTypeUnionReturnType */
public function returnType() : int|false {}

Expand All @@ -49,6 +67,12 @@ class TypeUnion

/* testTypeUnionReturnTypeNamespaceRelative */
public function identifierNamesReturnRelative() : namespace\Sub\NameA|namespace\Sub\NameB {}

/* testTypeUnionReturnPartiallyQualified */
public function identifierNamesReturnPQ() : Partially\Qualified\NameA|Partially\Qualified\NameB {}

/* testTypeUnionReturnFullyQualified */
public function identifierNamesReturnFQ() : \Fully\Qualified\NameA|\Fully\Qualified\NameB {}
}

/* testTypeUnionClosureParamIllegalNullable */
Expand Down
8 changes: 8 additions & 0 deletions Tests/Utils/Operators/IsTypeUnionTest.php
Expand Up @@ -77,14 +77,22 @@ public function dataIsTypeUnion()
'property-multi-type-1' => ['/* testTypeUnionPropertyMulti1 */'],
'property-multi-type-2' => ['/* testTypeUnionPropertyMulti2 */'],
'property-multi-type-3' => ['/* testTypeUnionPropertyMulti3 */'],
'property-namespace-operator' => ['/* testTypeUnionPropertyNamespaceRelative */'],
'property-partially-qualified' => ['/* testTypeUnionPropertyPartiallyQualified */'],
'property-fully-qualified' => ['/* testTypeUnionPropertyFullyQualified */'],
'parameter-multi-type-1' => ['/* testTypeUnionParam1 */'],
'parameter-multi-type-2' => ['/* testTypeUnionParam2 */'],
'parameter-multi-type-3' => ['/* testTypeUnionParam3 */'],
'parameter-namespace-operator' => ['/* testTypeUnionParamNamespaceRelative */'],
'parameter-partially-qualified' => ['/* testTypeUnionParamPartiallyQualified */'],
'parameter-fully-qualified' => ['/* testTypeUnionParamFullyQualified */'],
'return' => ['/* testTypeUnionReturnType */'],
'constructor-property-promotion' => ['/* testTypeUnionConstructorPropertyPromotion */'],
'return-abstract-method-1' => ['/* testTypeUnionAbstractMethodReturnType1 */'],
'return-abstract-method-2' => ['/* testTypeUnionAbstractMethodReturnType2 */'],
'return-namespace-operator' => ['/* testTypeUnionReturnTypeNamespaceRelative */'],
'return-partially-qualified' => ['/* testTypeUnionReturnPartiallyQualified */'],
'return-fully-qualified' => ['/* testTypeUnionReturnFullyQualified */'],
'parameter-closure-with-nullable' => ['/* testTypeUnionClosureParamIllegalNullable */'],
'return-closure' => ['/* testTypeUnionClosureReturn */'],
'parameter-arrow' => ['/* testTypeUnionArrowParam */'],
Expand Down

0 comments on commit 85f43a9

Please sign in to comment.