diff --git a/PHPCSUtils/BackCompat/BCFile.php b/PHPCSUtils/BackCompat/BCFile.php index 1ed1298f..121f8b24 100644 --- a/PHPCSUtils/BackCompat/BCFile.php +++ b/PHPCSUtils/BackCompat/BCFile.php @@ -111,6 +111,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * 'name' => '$var', // The variable name. * 'token' => integer, // The stack pointer to the variable name. * 'content' => string, // The full content of the variable definition. + * 'has_attributes' => boolean, // Does the parameter have one or more attributes attached ? * 'pass_by_reference' => boolean, // Is the variable passed by reference? * 'reference_token' => integer, // The stack pointer to the reference operator * // or FALSE if the param is not passed by reference. @@ -206,6 +207,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $defaultStart = null; $equalToken = null; $paramCount = 0; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; @@ -236,6 +238,12 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) } switch ($tokens[$i]['code']) { + case T_ATTRIBUTE: + $hasAttributes = true; + + // Skip to the end of the attribute. + $i = $tokens[$i]['attribute_closer']; + break; case T_BITWISE_AND: if ($defaultStart === null) { $passByReference = true; @@ -356,6 +364,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $vars[$paramCount]['default_equal_token'] = $equalToken; } + $vars[$paramCount]['has_attributes'] = $hasAttributes; $vars[$paramCount]['pass_by_reference'] = $passByReference; $vars[$paramCount]['reference_token'] = $referenceToken; $vars[$paramCount]['variable_length'] = $variableLength; @@ -381,6 +390,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $paramStart = ($i + 1); $defaultStart = null; $equalToken = null; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index 9ea9ed54..3f2ce862 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -41,9 +41,10 @@ class Arrays \T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, - // Inline function and control structures to skip over. + // Inline function, control structures and other things to skip over. \T_FN => \T_FN, \T_MATCH => \T_MATCH, + \T_ATTRIBUTE => \T_ATTRIBUTE, ]; /** @@ -297,6 +298,7 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortArray = * @since 1.0.0 * @since 1.0.0-alpha2 Now allows for arrow functions in arrays. * @since 1.0.0-alpha4 Now allows for match expressions in arrays. + * @since 1.0.0-alpha4 Now allows for attributes in arrays. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being examined. * @param int $start Stack pointer to the start of the array item. @@ -354,6 +356,14 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) continue; } + // Skip over attributes which may contain arrays as a passed parameters. + if ($tokens[$doubleArrow]['code'] === \T_ATTRIBUTE + && isset($tokens[$doubleArrow]['attribute_closer']) + ) { + $doubleArrow = $tokens[$doubleArrow]['attribute_closer']; + continue; + } + // Start of nested long/short array. break; } while ($doubleArrow < $end); diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 0ad5247d..f636b712 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -313,6 +313,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) * 'name' => '$var', // The variable name. * 'token' => integer, // The stack pointer to the variable name. * 'content' => string, // The full content of the variable definition. + * 'has_attributes' => boolean, // Does the parameter have one or more attributes attached ? * 'pass_by_reference' => boolean, // Is the variable passed by reference? * 'reference_token' => integer, // The stack pointer to the reference operator * // or FALSE if the param is not passed by reference. @@ -359,6 +360,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. * @since 1.0.0-alpha4 Added support for PHP 8.0 constructor property promotion. * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. + * @since 1.0.0-alpha4 Added support for PHP 8.0 parameter attributes. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token @@ -414,6 +416,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) $defaultStart = null; $equalToken = null; $paramCount = 0; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; @@ -439,6 +442,13 @@ public static function getParameters(File $phpcsFile, $stackPtr) } switch ($tokens[$i]['code']) { + case \T_ATTRIBUTE: + $hasAttributes = true; + + // Skip to the end of the attribute. + $i = $tokens[$i]['attribute_closer']; + break; + case \T_BITWISE_AND: $passByReference = true; $referenceToken = $i; @@ -488,6 +498,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) $vars[$paramCount]['default_equal_token'] = $equalToken; } + $vars[$paramCount]['has_attributes'] = $hasAttributes; $vars[$paramCount]['pass_by_reference'] = $passByReference; $vars[$paramCount]['reference_token'] = $referenceToken; $vars[$paramCount]['variable_length'] = $variableLength; @@ -513,6 +524,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) $paramStart = ($i + 1); $defaultStart = null; $equalToken = null; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; diff --git a/PHPCSUtils/Utils/Namespaces.php b/PHPCSUtils/Utils/Namespaces.php index fa64e458..e0165c14 100644 --- a/PHPCSUtils/Utils/Namespaces.php +++ b/PHPCSUtils/Utils/Namespaces.php @@ -285,6 +285,7 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) \T_CLOSE_SHORT_ARRAY, \T_CLOSE_SQUARE_BRACKET, \T_DOC_COMMENT_CLOSE_TAG, + \T_ATTRIBUTE_END, ]; $returnValue = false; @@ -327,6 +328,12 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) continue; } + // Skip over potentially large attributes. + if (isset($tokens[$prev]['attribute_opener'])) { + $prev = $tokens[$prev]['attribute_opener']; + continue; + } + // Skip over potentially large docblocks. if (isset($tokens[$prev]['comment_opener'])) { $prev = $tokens[$prev]['comment_opener']; diff --git a/PHPCSUtils/Utils/PassedParameters.php b/PHPCSUtils/Utils/PassedParameters.php index d6d3a612..726793eb 100644 --- a/PHPCSUtils/Utils/PassedParameters.php +++ b/PHPCSUtils/Utils/PassedParameters.php @@ -43,6 +43,7 @@ class PassedParameters \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_OPEN_PARENTHESIS => \T_OPEN_PARENTHESIS, \T_DOC_COMMENT_OPEN_TAG => \T_DOC_COMMENT_OPEN_TAG, + \T_ATTRIBUTE => \T_ATTRIBUTE, ]; /** @@ -270,6 +271,14 @@ public static function getParameters(File $phpcsFile, $stackPtr, $limit = 0, $is continue; } + // Skip over attributes. + if ($tokens[$nextComma]['code'] === \T_ATTRIBUTE + && isset($tokens[$nextComma]['attribute_closer']) + ) { + $nextComma = $tokens[$nextComma]['attribute_closer']; + continue; + } + if ($tokens[$nextComma]['code'] !== \T_COMMA && $tokens[$nextComma]['code'] !== $tokens[$closer]['code'] ) { diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index 1e7549d7..027e5e73 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -88,6 +88,7 @@ class Variables * * @since 1.0.0 * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. + * @since 1.0.0-alpha4 No longer gets confused by PHP 8.0 property attributes. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the `T_VARIABLE` token @@ -138,6 +139,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) \T_SEMICOLON, \T_OPEN_CURLY_BRACKET, \T_CLOSE_CURLY_BRACKET, + \T_ATTRIBUTE_END, ], ($stackPtr - 1) ); diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc index 0591824b..2782e77b 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc @@ -243,3 +243,19 @@ $anon = class() { // Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. public int |string| /*comment*/ INT $duplicateTypeInUnion; }; + +$anon = class { + /* testPHP8PropertySingleAttribute */ + #[PropertyWithAttribute] + public string $foo; + + /* testPHP8PropertyMultipleAttributes */ + #[PropertyWithAttribute(foo: 'bar'), MyAttribute] + protected ?int|float $bar; + + /* testPHP8PropertyMultilineAttribute */ + #[ + PropertyWithAttribute(/* comment */ 'baz') + ] + private mixed $baz; +}; diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php index 5d975a26..3e4bad15 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php @@ -764,6 +764,42 @@ public function dataGetMemberProperties() 'nullable_type' => false, ], ], + 'php8-property-with-single-attribute' => [ + '/* testPHP8PropertySingleAttribute */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'string', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-property-with-multiple-attributes' => [ + '/* testPHP8PropertyMultipleAttributes */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'type' => '?int|float', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8-property-with-multiline-attribute' => [ + '/* testPHP8PropertyMultilineAttribute */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'type' => 'mixed', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], ]; } diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index 35bb7398..91e57710 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -220,6 +220,20 @@ function commentsInParams( ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ 'default value' . /*-*/ 'second part' // Trailing comment. ) {} +/* testParameterAttributesInFunctionDeclaration */ +class ParametersWithAttributes( + public function __construct( + #[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute, + #[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute, + #[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute, + #[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes, + #[MyAttribute(array("key" => "value"))] + &...$otherParam, + ) {} +} + /* testFunctionCallFnPHPCS353-354 */ $value = $obj->fn(true); diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index 92aa712a..217a2ea4 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -162,6 +162,7 @@ public function testPassByReference() 'token' => 5, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => '&$var', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 4, // Offset from the T_FUNCTION token. 'variable_length' => false, @@ -188,6 +189,7 @@ public function testArrayHint() 'token' => 6, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'array $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -214,6 +216,7 @@ public function testVariable() 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => '$var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -243,6 +246,7 @@ public function testSingleDefaultValue() 'default' => 'self::CONSTANT', 'default_token' => 6, // Offset from the T_FUNCTION token. 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -272,6 +276,7 @@ public function testDefaultValues() 'default' => '1', 'default_token' => 6, // Offset from the T_FUNCTION token. 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -289,6 +294,7 @@ public function testDefaultValues() 'default' => "'value'", 'default_token' => 11, // 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, @@ -315,6 +321,7 @@ public function testTypeHint() 'token' => 6, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => 'foo $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -330,6 +337,7 @@ public function testTypeHint() 'token' => 11, // Offset from the T_FUNCTION token. 'name' => '$var2', 'content' => 'bar $var2', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -356,6 +364,7 @@ public function testSelfTypeHint() 'token' => 6, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'self $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -384,6 +393,7 @@ public function testNullableTypeHint() 'token' => 7, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => '?int $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -399,6 +409,7 @@ public function testNullableTypeHint() 'token' => ($php8Names === true) ? 13 : 14, // Offset from the T_FUNCTION token. 'name' => '$var2', 'content' => '?\bar $var2', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -428,6 +439,7 @@ public function testBitwiseAndConstantExpressionDefaultValue() 'default' => '10 & 20', 'default_token' => 8, // Offset from the T_FUNCTION token. 'default_equal_token' => 6, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -454,6 +466,7 @@ public function testArrowFunction() 'token' => 4, // Offset from the T_FN token. 'name' => '$a', 'content' => 'int $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -469,6 +482,7 @@ public function testArrowFunction() 'token' => 8, // Offset from the T_FN token. 'name' => '$b', 'content' => '...$b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -495,6 +509,7 @@ public function testArrowFunctionReturnByRef() 'token' => 6, // Offset from the T_FN token. 'name' => '$a', 'content' => '?string $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -524,6 +539,7 @@ public function testArrayDefaultValues() 'default' => '[]', 'default_token' => 8, // Offset from the T_FUNCTION token. 'default_equal_token' => 6, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -541,6 +557,7 @@ public function testArrayDefaultValues() 'default' => 'array(1, 2, 3)', 'default_token' => 16, // Offset from the T_FUNCTION token. 'default_equal_token' => 14, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -567,6 +584,7 @@ public function testConstantDefaultValueSecondParam() 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => '$var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -584,6 +602,7 @@ public function testConstantDefaultValueSecondParam() 'default' => 'M_PI', '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, @@ -613,6 +632,7 @@ public function testScalarTernaryExpressionInDefault() 'default' => 'FOO ? \'bar\' : 10', 'default_token' => 9, // Offset from the T_FUNCTION token. 'default_equal_token' => 7, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -627,6 +647,7 @@ public function testScalarTernaryExpressionInDefault() 'token' => 24, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => '? bool $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -653,6 +674,7 @@ public function testVariadicFunction() 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => 'int ... $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -679,6 +701,7 @@ public function testVariadicByRefFunction() 'token' => 7, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '&...$a', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 5, // Offset from the T_FUNCTION token. 'variable_length' => true, @@ -705,6 +728,7 @@ public function testVariadicFunctionClassType() 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$unit', 'content' => '$unit', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -719,6 +743,7 @@ public function testVariadicFunctionClassType() 'token' => 10, // Offset from the T_FUNCTION token. 'name' => '$intervals', 'content' => 'DateInterval ...$intervals', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -747,6 +772,7 @@ public function testNameSpacedTypeDeclaration() 'token' => ($php8Names === true) ? 7 : 12, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '\Package\Sub\ClassName $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -761,6 +787,7 @@ public function testNameSpacedTypeDeclaration() 'token' => ($php8Names === true) ? 13 : 20, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => '?Sub\AnotherClass $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -787,6 +814,7 @@ public function testWithAllTypes() 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '?ClassName $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -801,6 +829,7 @@ public function testWithAllTypes() 'token' => 15, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => 'self $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -815,6 +844,7 @@ public function testWithAllTypes() 'token' => 21, // Offset from the T_FUNCTION token. 'name' => '$c', 'content' => 'parent $c', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -829,6 +859,7 @@ public function testWithAllTypes() 'token' => 27, // Offset from the T_FUNCTION token. 'name' => '$d', 'content' => 'object $d', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -843,6 +874,7 @@ public function testWithAllTypes() 'token' => 34, // Offset from the T_FUNCTION token. 'name' => '$e', 'content' => '?int $e', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -857,6 +889,7 @@ public function testWithAllTypes() 'token' => 41, // Offset from the T_FUNCTION token. 'name' => '$f', 'content' => 'string &$f', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 40, // Offset from the T_FUNCTION token. 'variable_length' => false, @@ -871,6 +904,7 @@ public function testWithAllTypes() 'token' => 47, // Offset from the T_FUNCTION token. 'name' => '$g', 'content' => 'iterable $g', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -888,6 +922,7 @@ public function testWithAllTypes() 'default' => 'true', 'default_token' => 57, // Offset from the T_FUNCTION token. 'default_equal_token' => 55, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -905,6 +940,7 @@ public function testWithAllTypes() 'default' => "'is_null'", 'default_token' => 67, // Offset from the T_FUNCTION token. 'default_equal_token' => 65, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -922,6 +958,7 @@ public function testWithAllTypes() 'default' => '1.1', 'default_token' => 77, // Offset from the T_FUNCTION token. 'default_equal_token' => 75, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -936,6 +973,7 @@ public function testWithAllTypes() 'token' => 84, // Offset from the T_FUNCTION token. 'name' => '$k', 'content' => 'array ...$k', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -962,6 +1000,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 7, // Offset from the T_FN token. 'name' => '$a', 'content' => '?ClassName $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -976,6 +1015,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 13, // Offset from the T_FN token. 'name' => '$b', 'content' => 'self $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -990,6 +1030,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 19, // Offset from the T_FN token. 'name' => '$c', 'content' => 'parent $c', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1004,6 +1045,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 25, // Offset from the T_FN token. 'name' => '$d', 'content' => 'object $d', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1018,6 +1060,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 32, // Offset from the T_FN token. 'name' => '$e', 'content' => '?int $e', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1032,6 +1075,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 39, // Offset from the T_FN token. 'name' => '$f', 'content' => 'string &$f', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 38, // Offset from the T_FN token. 'variable_length' => false, @@ -1046,6 +1090,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 45, // Offset from the T_FN token. 'name' => '$g', 'content' => 'iterable $g', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1063,6 +1108,7 @@ public function testArrowFunctionWithAllTypes() 'default' => 'true', 'default_token' => 55, // Offset from the T_FN token. 'default_equal_token' => 53, // Offset from the T_FN token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1080,6 +1126,7 @@ public function testArrowFunctionWithAllTypes() 'default' => "'is_null'", 'default_token' => 65, // Offset from the T_FN token. 'default_equal_token' => 63, // Offset from the T_FN token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1097,6 +1144,7 @@ public function testArrowFunctionWithAllTypes() 'default' => '1.1', 'default_token' => 75, // Offset from the T_FN token. 'default_equal_token' => 73, // Offset from the T_FN token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1111,6 +1159,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 82, // Offset from the T_FN token. 'name' => '$k', 'content' => 'array ...$k', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -1142,6 +1191,7 @@ public function testMessyDeclaration() ?\MyNS /* comment */ \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. \ MyClass $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1159,6 +1209,7 @@ public function testMessyDeclaration() 'default' => "'default' /* test*/", 'default_token' => ($php8Names === true) ? 36 : 37, // Offset from the T_FUNCTION token. 'default_equal_token' => ($php8Names === true) ? 32 : 33, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1176,6 +1227,7 @@ public function testMessyDeclaration() ? /*comment*/ bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. & /*test*/ ... /* phpcs:ignore */ $c', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => ($php8Names === true) ? 53 : 54, // Offset from the T_FUNCTION token. 'variable_length' => true, @@ -1202,6 +1254,7 @@ public function testPHP8MixedTypeHint() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => 'mixed &...$var1', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 6, // Offset from the T_FUNCTION token. 'variable_length' => true, @@ -1228,6 +1281,7 @@ public function testPHP8MixedTypeHintNullable() 'token' => 7, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => '?Mixed $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1256,6 +1310,7 @@ public function testNamespaceOperatorTypeHint() 'token' => ($php8Names === true) ? 7 : 9, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => '?namespace\Name $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1282,6 +1337,7 @@ public function testPHP8UnionTypesSimple() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$number', 'content' => 'int|float $number', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1296,6 +1352,7 @@ public function testPHP8UnionTypesSimple() 'token' => 17, // Offset from the T_FUNCTION token. 'name' => '$obj', 'content' => 'self|parent &...$obj', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 15, // Offset from the T_FUNCTION token. 'variable_length' => true, @@ -1322,6 +1379,7 @@ public function testPHP8UnionTypesWithSpreadOperatorAndReference() 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$paramA', 'content' => 'float|null &$paramA', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 8, // Offset from the T_FUNCTION token. 'variable_length' => false, @@ -1336,6 +1394,7 @@ public function testPHP8UnionTypesWithSpreadOperatorAndReference() 'token' => 17, // Offset from the T_FUNCTION token. 'name' => '$paramB', 'content' => 'string|int ...$paramB', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -1364,7 +1423,8 @@ public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', 'default' => 'CONSTANT_A | CONSTANT_B', 'default_token' => 10, // Offset from the T_FUNCTION token. - 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1393,6 +1453,7 @@ public function testPHP8UnionTypesTwoClasses() 'token' => ($php8Names === true) ? 8 : 11, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'MyClassA|\Package\MyClassB $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1419,6 +1480,7 @@ public function testPHP8UnionTypesAllBaseTypes() 'token' => 20, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'array|bool|callable|int|float|null|object|string $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1447,6 +1509,7 @@ public function testPHP8UnionTypesAllPseudoTypes() 'token' => 16, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'false|mixed|self|parent|iterable|Resource $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1473,6 +1536,7 @@ public function testPHP8UnionTypesNullable() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$number', 'content' => '?int|float $number', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1502,6 +1566,7 @@ public function testPHP8PseudoTypeNull() 'default' => 'null', 'default_token' => 10, // Offset from the T_FUNCTION token. 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1531,6 +1596,7 @@ public function testPHP8PseudoTypeFalse() 'default' => 'false', 'default_token' => 10, // Offset from the T_FUNCTION token. 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1560,6 +1626,7 @@ public function testPHP8PseudoTypeFalseAndBool() 'default' => 'false', '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, @@ -1586,6 +1653,7 @@ public function testPHP8ObjectAndClass() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'object|ClassName $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1612,6 +1680,7 @@ public function testPHP8PseudoTypeIterableAndArray() 'token' => 10, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'iterable|array|Traversable $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1638,6 +1707,7 @@ public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() 'token' => 17, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'int | string /*comment*/ | INT $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1667,6 +1737,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes() 'default' => '0.0', '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, @@ -1686,6 +1757,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes() 'default' => "''", 'default_token' => 22, // Offset from the T_FUNCTION token. 'default_equal_token' => 20, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1705,6 +1777,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes() 'default' => 'null', 'default_token' => 32, // Offset from the T_FUNCTION token. 'default_equal_token' => 30, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1733,6 +1806,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes() 'token' => 10, // Offset from the T_FUNCTION token. 'name' => '$x', 'content' => 'protected float|int $x', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1752,6 +1826,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes() 'default' => "'test'", 'default_token' => 23, // Offset from the T_FUNCTION token. 'default_equal_token' => 21, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 18, // Offset from the T_FUNCTION token. 'variable_length' => false, @@ -1768,6 +1843,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes() 'token' => 30, // Offset from the T_FUNCTION token. 'name' => '$z', 'content' => 'private mixed $z', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1796,6 +1872,7 @@ public function testPHP8ConstructorPropertyPromotionAndNormalParam() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$promotedProp', 'content' => 'public int $promotedProp', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1812,6 +1889,7 @@ public function testPHP8ConstructorPropertyPromotionAndNormalParam() 'token' => 14, // Offset from the T_FUNCTION token. 'name' => '$normalArg', 'content' => '?int $normalArg', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1838,6 +1916,7 @@ public function testPHP8ConstructorPropertyPromotionGlobalFunction() 'token' => 6, // Offset from the T_FUNCTION token. 'name' => '$x', 'content' => 'private $x', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1866,6 +1945,7 @@ public function testPHP8ConstructorPropertyPromotionAbstractMethod() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$y', 'content' => 'public callable $y', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1882,6 +1962,7 @@ public function testPHP8ConstructorPropertyPromotionAbstractMethod() 'token' => 14, // Offset from the T_FUNCTION token. 'name' => '$x', 'content' => 'private ...$x', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -1914,6 +1995,7 @@ public function testCommentsInParameter() 'default' => '\'default value\' . /*-*/ \'second part\' // Trailing comment.', 'default_token' => 27, // Offset from the T_FUNCTION token. 'default_equal_token' => 23, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 13, // Offset from the T_FUNCTION token. 'variable_length' => true, @@ -1928,6 +2010,101 @@ public function testCommentsInParameter() $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify behaviour when parameters have attributes attached. + * + * @return void + */ + public function testParameterAttributesInFunctionDeclaration() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => ($php8Names === true) ? 14 : 17, // Offset from the T_FUNCTION token. + 'name' => '$constructorPropPromTypedParamSingleAttribute', + 'content' => '#[\MyExample\MyAttribute] private string' + . ' $constructorPropPromTypedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => ($php8Names === true) ? 12 : 15, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 12 : 15, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => ($php8Names === true) ? 10 : 13, // Offset from the T_FUNCTION token. + 'comma_token' => ($php8Names === true) ? 15 : 18, // Offset from the T_FUNCTION token. + ]; + $expected[1] = [ + 'token' => ($php8Names === true) ? 36 : 39, // Offset from the T_FUNCTION token. + 'name' => '$typedParamSingleAttribute', + 'content' => '#[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Type|false', + 'type_hint_token' => ($php8Names === true) ? 31 : 34, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 33 : 36, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 37 : 40, // Offset from the T_FUNCTION token. + ]; + $expected[2] = [ + 'token' => ($php8Names === true) ? 56 : 59, // Offset from the T_FUNCTION token. + 'name' => '$nullableTypedParamMultiAttribute', + 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => ($php8Names === true) ? 54 : 57, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 54 : 57, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => ($php8Names === true) ? 57 : 60, // Offset from the T_FUNCTION token. + ]; + $expected[3] = [ + 'token' => ($php8Names === true) ? 71 : 74, // Offset from the T_FUNCTION token. + 'name' => '$nonTypedParamTwoAttributes', + 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 72 : 75, // Offset from the T_FUNCTION token. + ]; + $expected[4] = [ + 'token' => ($php8Names === true) ? 92 : 95, // Offset from the T_FUNCTION token. + 'name' => '$otherParam', + 'content' => '#[MyAttribute(array("key" => "value"))] + &...$otherParam', + 'has_attributes' => true, + 'pass_by_reference' => true, + 'reference_token' => ($php8Names === true) ? 90 : 93, // Offset from the T_FUNCTION token. + 'variable_length' => true, + 'variadic_token' => ($php8Names === true) ? 91 : 94, // Offset from the T_FUNCTION token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 93 : 96, // Offset from the T_FUNCTION token. + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Verify handling of a closure. * @@ -1943,6 +2120,7 @@ public function testClosure() 'default' => "'test'", 'default_token' => 7, // Offset from the T_FUNCTION token. 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1969,6 +2147,7 @@ public function testClosureUse() 'token' => 3, // Offset from the T_USE token. 'name' => '$foo', 'content' => '$foo', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1983,6 +2162,7 @@ public function testClosureUse() 'token' => 6, // Offset from the T_USE token. 'name' => '$bar', 'content' => '$bar', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2009,6 +2189,7 @@ public function testFunctionParamListWithTrailingComma() 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$foo', 'content' => '?string $foo /*comment*/', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2026,6 +2207,7 @@ public function testFunctionParamListWithTrailingComma() 'default' => '0', 'default_token' => 20, // Offset from the T_FUNCTION token. 'default_equal_token' => 18, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2052,6 +2234,7 @@ public function testClosureParamListWithTrailingComma() 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$foo', 'content' => '$foo', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2066,6 +2249,7 @@ public function testClosureParamListWithTrailingComma() 'token' => 8, // Offset from the T_FUNCTION token. 'name' => '$bar', 'content' => '$bar', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2092,6 +2276,7 @@ public function testArrowFunctionParamListWithTrailingComma() 'token' => 6, // Offset from the T_FN token. 'name' => '$a', 'content' => '?int $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2106,6 +2291,7 @@ public function testArrowFunctionParamListWithTrailingComma() 'token' => 11, // Offset from the T_FN token. 'name' => '$b', 'content' => '...$b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -2132,6 +2318,7 @@ public function testClosureUseWithTrailingComma() 'token' => 4, // Offset from the T_USE token. 'name' => '$foo', 'content' => '$foo /*comment*/', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -2146,6 +2333,7 @@ public function testClosureUseWithTrailingComma() 'token' => 11, // Offset from the T_USE token. 'name' => '$bar', 'content' => '$bar', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc index 40909d7d..c0e6a866 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc @@ -105,6 +105,12 @@ $array = [ default => [0 => 10], } => 'value', + /* testNoArrowValueClosureWithAttribute */ + #[MyAttribute([0 => 'value'])] function() { /* do something */ }(), + + /* testArrowKeyClosureWithAttribute */ + #[MyAttribute([0 => 'value'])] function() { /* do something */ }() => 'value', + /* testEmptyArrayItem */ // Intentional parse error. , diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index ae20eda8..3d1ff49c 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -234,6 +234,16 @@ public function dataGetDoubleArrowPtr() 'expected' => 38, ], + // Safeguard that double arrows in PHP 8.0 attributes are disregarded. + 'test-no-arrow-value-closure-with-attached-attribute-containing-arrow' => [ + 'testMarker' => '/* testNoArrowValueClosureWithAttribute */', + 'expected' => false, + ], + 'test-double-arrow-key-closure-with-attached-attribute-containing-arrow' => [ + 'testMarker' => '/* testArrowKeyClosureWithAttribute */', + 'expected' => 31, + ], + 'test-empty-array-item' => [ 'testMarker' => '/* testEmptyArrayItem */', 'expected' => false, diff --git a/Tests/Utils/Namespaces/DetermineNamespaceTest.inc b/Tests/Utils/Namespaces/DetermineNamespaceTest.inc index 911813af..e99c5561 100644 --- a/Tests/Utils/Namespaces/DetermineNamespaceTest.inc +++ b/Tests/Utils/Namespaces/DetermineNamespaceTest.inc @@ -114,7 +114,12 @@ echo 0; /** * Docblock to skip over. */ +#[ + AttributeToSkipOver, + AnotherAttribute, +] class Foo { + #[AttributeToSkipOver()] #[AnotherAttribute] function test() { /* testNonScopedNamedNamespace2Nested */ echo 0; diff --git a/Tests/Utils/PassedParameters/GetParametersTest.inc b/Tests/Utils/PassedParameters/GetParametersTest.inc index 5f4b88bb..593dd19f 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.inc +++ b/Tests/Utils/PassedParameters/GetParametersTest.inc @@ -131,3 +131,15 @@ $arr4 = array(...$arr1, ...arrGen(), ...new ArrayIterator(['a', 'b', 'c'])); /* testPHP74UnpackingInShortArrayExpression */ // Also includes code sample for PHP 8.1 unpacking with string keys. $fruits = ['banana', ...$parts, 'watermelon', ...["a" => 2],]; + +/* testPHP80FunctionCallInAttribute */ +#[AttributeAttachedToClosure([1, 2, 3])] +$closure = function() {}; + +/* testPHP80SkippingOverAttributes */ +$result = function_call( + $value, + #[MyAttribute()] + #[AnotherAttribute([1, 2, 3])] + function() { /* do something */} +); diff --git a/Tests/Utils/PassedParameters/GetParametersTest.php b/Tests/Utils/PassedParameters/GetParametersTest.php index 541a07b8..a7274514 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.php +++ b/Tests/Utils/PassedParameters/GetParametersTest.php @@ -587,6 +587,39 @@ public function test( $foo, $bar ) { ], ], ], + + // PHP 8.0: function calls in attributes. + 'function-call-within-an-attribute' => [ + 'testMarker' => '/* testPHP80FunctionCallInAttribute */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 10, + 'raw' => '[1, 2, 3]', + ], + ], + ], + + // PHP 8.0: skipping over attributes. + 'function-call-with-attributes-attached-to-passed-closure' => [ + 'testMarker' => '/* testPHP80SkippingOverAttributes */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 4, + 'raw' => '$value', + ], + 2 => [ + 'start' => 6, + 'end' => 39, + 'raw' => '#[MyAttribute()] + #[AnotherAttribute([1, 2, 3])] + function() { /* do something */}', + ], + ], + ], ]; }