Skip to content

PassedParameters::hasParameters(): account for upstream tokenization change for parent #328

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

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
3 changes: 1 addition & 2 deletions PHPCSUtils/Tokens/Collections.php
Original file line number Diff line number Diff line change
Expand Up @@ -654,8 +654,7 @@ public static function functionCallTokens()

// Class instantiation only.
$tokens[\T_ANON_CLASS] = \T_ANON_CLASS;
$tokens[\T_SELF] = \T_SELF;
$tokens[\T_STATIC] = \T_STATIC;
$tokens += self::ooHierarchyKeywords();

return $tokens;
}
Expand Down
5 changes: 3 additions & 2 deletions PHPCSUtils/Utils/PassedParameters.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class PassedParameters
* If a `T_STRING` or `T_VARIABLE` which is *not* a function call is passed, the behaviour is
* undetermined.
* - If passed a `T_ANON_CLASS` stack pointer, it will accept it as a class instantiation.
* - If passed a `T_SELF` or `T_STATIC` stack pointer, it will accept it as a
* - If passed a `T_SELF`, `T_STATIC` or `T_PARENT` stack pointer, it will accept it as a
* class instantiation function call when used like `new self()`.
* - If passed a `T_ARRAY` or `T_OPEN_SHORT_ARRAY` stack pointer, it will detect
* whether the array has values or is empty.
Expand Down Expand Up @@ -89,7 +89,8 @@ public static function hasParameters(File $phpcsFile, $stackPtr, $isShortArray =
);
}

if ($tokens[$stackPtr]['code'] === \T_SELF || $tokens[$stackPtr]['code'] === \T_STATIC) {
// Reminder: `new parent` only tokenizes as `T_PARENT` since PHPCS 3.7.0.
if (isset(Collections::ooHierarchyKeywords()[$tokens[$stackPtr]['code']]) === true) {
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
if ($tokens[$prev]['code'] !== \T_NEW) {
throw new RuntimeException(
Expand Down
1 change: 1 addition & 0 deletions Tests/Tokens/Collections/FunctionCallTokensTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function testFunctionCallTokens()
$expected += [
\T_VARIABLE => \T_VARIABLE,
\T_ANON_CLASS => \T_ANON_CLASS,
\T_PARENT => \T_PARENT,
\T_SELF => \T_SELF,
\T_STATIC => \T_STATIC,
];
Expand Down
1 change: 1 addition & 0 deletions Tests/Tokens/Collections/ParameterPassingTokensTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function testParameterPassingTokens()
$expected += [
\T_VARIABLE => \T_VARIABLE,
\T_ANON_CLASS => \T_ANON_CLASS,
\T_PARENT => \T_PARENT,
\T_SELF => \T_SELF,
\T_STATIC => \T_STATIC,
\T_ISSET => \T_ISSET,
Expand Down
42 changes: 38 additions & 4 deletions Tests/Utils/PassedParameters/HasParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ interface NotAFunctionCallOrArray {}

class Foo {
public function Bar() {
/* testNotACallToConstructor */
$a = self::some_method();
/* testNotACallToConstructor1 */
$a = parent::SOME_CONSTANT;

/* testNotACallToConstructor2 */
$a = static::some_method();

/* testNotACallToConstructor3 */
$a = $obj instanceof self;
}
}

Expand All @@ -27,6 +33,17 @@ some_function( /*nothing here*/ );
/* testNoParamsFunctionCall4 */
$closure(/*nothing here*/);

class HierarchyKeywordsNoParens {
public static function getInstance() {
/* testNoParamsFunctionCall5 */
$a = new self;
/* testNoParamsFunctionCall6 */
$a = new static;
/* testNoParamsFunctionCall7 */
$a = new parent;
}
}

// Function calls: has parameters.

/* testHasParamsFunctionCall1 */
Expand All @@ -35,10 +52,27 @@ some_function( 1 );
/* testHasParamsFunctionCall2 */
$closure(1,2,3);

class Bar {
class HierarchyKeywordsWithParam {
public static function getInstance() {
/* testHasParamsFunctionCall3 */
return new self(true);
$a = new self(true);
/* testHasParamsFunctionCall4 */
$a = new static(true);
/* testHasParamsFunctionCall5 */
$a = new parent(true);
}
}

class HierarchyKeywordsAsMethodNames {
public function self() {}
public function static() {}
public function parent() {
/* testHasParamsFunctionCall6 */
$a = self::self(true);
/* testHasParamsFunctionCall7 */
$a = $this->static(true);
/* testHasParamsFunctionCall8 */
$a = $this->parent(true);
}
}

Expand Down
84 changes: 81 additions & 3 deletions Tests/Utils/PassedParameters/HasParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,48 @@ public function testNotAnAcceptedTokenException()
/**
* Test receiving an expected exception when T_SELF is passed not preceeded by `new`.
*
* @dataProvider dataNotACallToConstructor
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param int|string $targetType The type of token to look for.
*
* @return void
*/
public function testNotACallToConstructor()
public function testNotACallToConstructor($testMarker, $targetType)
{
$this->expectPhpcsException(
'The hasParameters() method expects a function call, array, isset or unset token to be passed.'
);

$self = $this->getTargetToken('/* testNotACallToConstructor */', \T_SELF);
$self = $this->getTargetToken($testMarker, $targetType);
PassedParameters::hasParameters(self::$phpcsFile, $self);
}

/**
* Data provider.
*
* @see testNotACallToConstructor() For the array format.
*
* @return array
*/
public function dataNotACallToConstructor()
{
return [
'parent' => [
'testMarker' => '/* testNotACallToConstructor1 */',
'targetType' => \T_PARENT,
],
'static' => [
'testMarker' => '/* testNotACallToConstructor2 */',
'targetType' => \T_STATIC,
],
'self' => [
'testMarker' => '/* testNotACallToConstructor3 */',
'targetType' => \T_SELF,
],
];
}

/**
* Test receiving an expected exception when T_OPEN_SHORT_ARRAY is passed but represents a short list.
*
Expand Down Expand Up @@ -141,6 +171,24 @@ public function dataHasParameters()
\T_VARIABLE,
false,
],
'no-params-function-call-5-new-self' => [
'/* testNoParamsFunctionCall5 */',
// In PHPCS < 2.8.0, self in "new self" is tokenized as T_STRING.
[\T_SELF, \T_STRING],
false,
],
'no-params-function-call-6-new-static' => [
'/* testNoParamsFunctionCall6 */',
\T_STATIC,
false,
],
'no-params-function-call-7-new-parent' => [
'/* testNoParamsFunctionCall7 */',
// In PHPCS < 3.7.0, parent in "new parent" is tokenized as T_STRING.
[\T_PARENT, \T_STRING],
false,
],

'has-params-function-call-1' => [
'/* testHasParamsFunctionCall1 */',
\T_STRING,
Expand All @@ -151,12 +199,42 @@ public function dataHasParameters()
\T_VARIABLE,
true,
],
'has-params-function-call-3' => [
'has-params-function-call-3-new-self' => [
'/* testHasParamsFunctionCall3 */',
// In PHPCS < 2.8.0, self in "new self" is tokenized as T_STRING.
[\T_SELF, \T_STRING],
true,
],
'has-params-function-call-4-new-static' => [
'/* testHasParamsFunctionCall4 */',
\T_STATIC,
true,
],
'has-params-function-call-5-new-parent' => [
'/* testHasParamsFunctionCall5 */',
// In PHPCS < 3.7.0, parent in "new parent" is tokenized as T_STRING.
[\T_PARENT, \T_STRING],
true,
],
'has-params-function-call-6-self-as-method-name' => [
'/* testHasParamsFunctionCall6 */',
\T_STRING,
true,
'self',
],
'has-params-function-call-7-static-as-method-name' => [
'/* testHasParamsFunctionCall7 */',
\T_STRING,
true,
'static',
],
'has-params-function-call-8-parent-as-method-name' => [
'/* testHasParamsFunctionCall8 */',
\T_STRING,
true,
'parent',
],

'no-params-function-call-fully-qualified' => [
'/* testNoParamsFunctionCallFullyQualified */',
($php8Names === true) ? \T_NAME_FULLY_QUALIFIED : \T_STRING,
Expand Down