Skip to content
Merged
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
10 changes: 10 additions & 0 deletions PHPCSUtils/BackCompat/BCFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
12 changes: 11 additions & 1 deletion PHPCSUtils/Utils/Arrays.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
];

/**
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions PHPCSUtils/Utils/FunctionDeclarations.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions PHPCSUtils/Utils/Namespaces.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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'];
Expand Down
9 changes: 9 additions & 0 deletions PHPCSUtils/Utils/PassedParameters.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
];

/**
Expand Down Expand Up @@ -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']
) {
Expand Down
2 changes: 2 additions & 0 deletions PHPCSUtils/Utils/Variables.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
);
Expand Down
16 changes: 16 additions & 0 deletions Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
36 changes: 36 additions & 0 deletions Tests/BackCompat/BCFile/GetMemberPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
],
],
];
}

Expand Down
14 changes: 14 additions & 0 deletions Tests/BackCompat/BCFile/GetMethodParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading