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
46 changes: 44 additions & 2 deletions PHPCSUtils/BackCompat/BCFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ final class BCFile
*
* Changelog for the PHPCS native function:
* - Introduced in PHPCS 0.0.5.
* - The upstream method has received no significant updates since PHPCS 3.10.1.
* - PHPCS 3.12.0: hardening to handle unfinished closure better.
*
* @see \PHP_CodeSniffer\Files\File::getDeclarationName() Original source.
* @see \PHPCSUtils\Utils\ObjectDeclarations::getName() PHPCSUtils native improved version.
Expand All @@ -98,7 +98,49 @@ final class BCFile
*/
public static function getDeclarationName(File $phpcsFile, $stackPtr)
{
return $phpcsFile->getDeclarationName($stackPtr);
$tokens = $phpcsFile->getTokens();

$tokenCode = $tokens[$stackPtr]['code'];

if ($tokenCode === T_ANON_CLASS || $tokenCode === T_CLOSURE) {
return null;
}

if ($tokenCode !== T_FUNCTION
&& $tokenCode !== T_CLASS
&& $tokenCode !== T_INTERFACE
&& $tokenCode !== T_TRAIT
&& $tokenCode !== T_ENUM
) {
throw new RuntimeException('Token type "' . $tokens[$stackPtr]['type'] . '" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM');
}

if ($tokenCode === T_FUNCTION
&& strtolower($tokens[$stackPtr]['content']) !== 'function'
) {
// This is a function declared without the "function" keyword.
// So this token is the function name.
return $tokens[$stackPtr]['content'];
}

$stopPoint = $phpcsFile->numTokens;
if (isset($tokens[$stackPtr]['parenthesis_opener']) === true) {
// For functions, stop searching at the parenthesis opener.
$stopPoint = $tokens[$stackPtr]['parenthesis_opener'];
} elseif (isset($tokens[$stackPtr]['scope_opener']) === true) {
// For OO tokens, stop searching at the open curly.
$stopPoint = $tokens[$stackPtr]['scope_opener'];
}

$content = null;
for ($i = $stackPtr; $i < $stopPoint; $i++) {
if ($tokens[$i]['code'] === T_STRING) {
$content = $tokens[$i]['content'];
break;
}
}

return $content;
}

/**
Expand Down
5 changes: 5 additions & 0 deletions Tests/BackCompat/BCFile/GetDeclarationNameParseError1Test.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

/* testLiveCoding */
// Intentional parse error. This must be the only test in the file.
function // Comment.
61 changes: 61 additions & 0 deletions Tests/BackCompat/BCFile/GetDeclarationNameParseError1Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/

namespace PHPCSUtils\Tests\BackCompat\BCFile;

use PHPCSUtils\BackCompat\BCFile;
use PHPCSUtils\Tests\PolyfilledTestCase;

/**
* Tests for the \PHPCSUtils\BackCompat\BCFile::getDeclarationName() method.
*
* @covers \PHPCSUtils\BackCompat\BCFile::getDeclarationName
*
* @group objectdeclarations
*
* @since 1.0.0
*/
class GetDeclarationNameParseError1Test extends PolyfilledTestCase
{

/**
* Test receiving "null" in case of a parse error.
*
* @dataProvider dataGetDeclarationNameNull
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param int|string $targetType Token type of the token to get as stackPtr.
*
* @return void
*/
public function testGetDeclarationNameNull($testMarker, $targetType)
{
$target = $this->getTargetToken($testMarker, $targetType);
$result = BCFile::getDeclarationName(self::$phpcsFile, $target);
$this->assertNull($result);
}

/**
* Data provider.
*
* @see testGetDeclarationNameNull() For the array format.
*
* @return array<string, array<string, int|string>>
*/
public static function dataGetDeclarationNameNull()
{
return [
'unfinished function/live coding' => [
'testMarker' => '/* testLiveCoding */',
'targetType' => \T_FUNCTION,
],
];
}
}
6 changes: 6 additions & 0 deletions Tests/BackCompat/BCFile/GetDeclarationNameParseError2Test.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

/* testLiveCoding */
// Intentional parse error/live coding. This must be the only test in the file.
// Safeguarding that the utility method does not confuse the `string` type with a function name.
$closure = function (string $param) use ($var
61 changes: 61 additions & 0 deletions Tests/BackCompat/BCFile/GetDeclarationNameParseError2Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/

namespace PHPCSUtils\Tests\BackCompat\BCFile;

use PHPCSUtils\BackCompat\BCFile;
use PHPCSUtils\Tests\PolyfilledTestCase;

/**
* Tests for the \PHPCSUtils\BackCompat\BCFile::getDeclarationName() method.
*
* @covers \PHPCSUtils\BackCompat\BCFile::getDeclarationName
*
* @group objectdeclarations
*
* @since 1.1.0
*/
class GetDeclarationNameParseError2Test extends PolyfilledTestCase
{

/**
* Test receiving "null" in case of a parse error.
*
* @dataProvider dataGetDeclarationNameNull
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param int|string $targetType Token type of the token to get as stackPtr.
*
* @return void
*/
public function testGetDeclarationNameNull($testMarker, $targetType)
{
$target = $this->getTargetToken($testMarker, $targetType);
$result = BCFile::getDeclarationName(self::$phpcsFile, $target);
$this->assertNull($result);
}

/**
* Data provider.
*
* @see testGetDeclarationNameNull() For the array format.
*
* @return array<string, array<string, int|string>>
*/
public static function dataGetDeclarationNameNull()
{
return [
'unfinished closure/live coding' => [
'testMarker' => '/* testLiveCoding */',
'targetType' => \T_FUNCTION,
],
];
}
}
4 changes: 0 additions & 4 deletions Tests/BackCompat/BCFile/GetDeclarationNameTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,3 @@ function &self() {}

/* testFunctionReturnByRefWithReservedKeywordStatic */
function &static() {}

/* testLiveCoding */
// Intentional parse error. This has to be the last test in the file.
function // Comment.
4 changes: 0 additions & 4 deletions Tests/BackCompat/BCFile/GetDeclarationNameTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@ public static function dataGetDeclarationNameNull()
'testMarker' => '/* testAnonClassExtendsWithoutParens */',
'targetType' => \T_ANON_CLASS,
],
'live-coding' => [
'testMarker' => '/* testLiveCoding */',
'targetType' => \T_FUNCTION,
],
];
}

Expand Down
66 changes: 66 additions & 0 deletions Tests/Utils/ObjectDeclarations/GetNameParseError1Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/

namespace PHPCSUtils\Tests\Utils\ObjectDeclarations;

use PHPCSUtils\Tests\BackCompat\BCFile\GetDeclarationNameParseError1Test as BCFile_GetDeclarationNameParseError1Test;
use PHPCSUtils\Utils\ObjectDeclarations;

/**
* Tests for the \PHPCSUtils\Utils\ObjectDeclarations::getName() method.
*
* @covers \PHPCSUtils\Utils\ObjectDeclarations::getName
*
* @group objectdeclarations
*
* @since 1.0.0
*/
final class GetNameParseError1Test extends BCFile_GetDeclarationNameParseError1Test
{

/**
* Full path to the test case file associated with this test class.
*
* @var string
*/
protected static $caseFile = '';

/**
* Initialize PHPCS & tokenize the test case file.
*
* Overloaded to re-use the `$caseFile` from the BCFile test.
*
* @beforeClass
*
* @return void
*/
public static function setUpTestFile()
{
self::$caseFile = \dirname(\dirname(__DIR__)) . '/BackCompat/BCFile/GetDeclarationNameParseError1Test.inc';
parent::setUpTestFile();
}

/**
* Test receiving "null" in case of a parse error.
*
* @dataProvider dataGetDeclarationNameNull
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param int|string $targetType Token type of the token to get as stackPtr.
*
* @return void
*/
public function testGetDeclarationNameNull($testMarker, $targetType)
{
$target = $this->getTargetToken($testMarker, $targetType);
$result = ObjectDeclarations::getName(self::$phpcsFile, $target);
$this->assertNull($result);
}
}
66 changes: 66 additions & 0 deletions Tests/Utils/ObjectDeclarations/GetNameParseError2Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/

namespace PHPCSUtils\Tests\Utils\ObjectDeclarations;

use PHPCSUtils\Tests\BackCompat\BCFile\GetDeclarationNameParseError2Test as BCFile_GetDeclarationNameParseError2Test;
use PHPCSUtils\Utils\ObjectDeclarations;

/**
* Tests for the \PHPCSUtils\Utils\ObjectDeclarations::getName() method.
*
* @covers \PHPCSUtils\Utils\ObjectDeclarations::getName
*
* @group objectdeclarations
*
* @since 1.0.0
*/
final class GetNameParseError2Test extends BCFile_GetDeclarationNameParseError2Test
{

/**
* Full path to the test case file associated with this test class.
*
* @var string
*/
protected static $caseFile = '';

/**
* Initialize PHPCS & tokenize the test case file.
*
* Overloaded to re-use the `$caseFile` from the BCFile test.
*
* @beforeClass
*
* @return void
*/
public static function setUpTestFile()
{
self::$caseFile = \dirname(\dirname(__DIR__)) . '/BackCompat/BCFile/GetDeclarationNameParseError2Test.inc';
parent::setUpTestFile();
}

/**
* Test receiving "null" in case of a parse error.
*
* @dataProvider dataGetDeclarationNameNull
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param int|string $targetType Token type of the token to get as stackPtr.
*
* @return void
*/
public function testGetDeclarationNameNull($testMarker, $targetType)
{
$target = $this->getTargetToken($testMarker, $targetType);
$result = ObjectDeclarations::getName(self::$phpcsFile, $target);
$this->assertNull($result);
}
}