diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index e40b9999..911ca619 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -765,6 +765,8 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) if (isset($tokens[$scopeCloser]['scope_closer']) === true && $tokens[$scopeCloser]['code'] !== \T_INLINE_ELSE + && $tokens[$scopeCloser]['code'] !== \T_END_HEREDOC + && $tokens[$scopeCloser]['code'] !== \T_END_NOWDOC ) { // We minus 1 here in case the closer can be shared with us. $scopeCloser = ($tokens[$scopeCloser]['scope_closer'] - 1); diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc new file mode 100644 index 00000000..754a689f --- /dev/null +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.inc @@ -0,0 +1,11 @@ + << <<<'HTML' +fn +HTML; diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php new file mode 100644 index 00000000..ca2431fd --- /dev/null +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php @@ -0,0 +1,182 @@ + true, + '3.5.4' => true, + '3.5.5' => true, + ]; + + /** + * Whether the test case file has been tokenized. + * + * Efficiency tweak as the tokenization is done in "before" not in "before class" + * for this test. + * + * @var bool + */ + private static $tokenized = false; + + /** + * Do NOT Initialize PHPCS & tokenize the test case file. + * + * Skip tokenizing the test case file on "before class" as at that time, we can't skip the test + * yet if the PHPCS version in incompatible and it would hang the Tokenizer (and therefore + * the test) if it is. + * + * @beforeClass + * + * @return void + */ + public static function setUpTestFile() + { + // Skip the tokenizing of the test case file at this time. + } + + /** + * Initialize PHPCS & tokenize the test case file on compatible PHPCS versions. + * + * Skip this test on PHPCS versions on which the Tokenizer will hang. + * + * @before + * + * @return void + */ + public function setUpTestFileForReal() + { + $phpcsVersion = Helper::getVersion(); + + if (isset($this->unsupportedPHPCSVersions[$phpcsVersion]) === true) { + $this->markTestSkipped("Issue 2926 can not be tested on PHPCS $phpcsVersion as the Tokenizer will hang."); + } + + if (self::$tokenized === false) { + parent::setUpTestFile(); + self::$tokenized = true; + } + } + + /** + * Test correctly detecting arrow functions. + * + * @dataProvider dataArrowFunction + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected The expected return value for the respective functions. + * @param array $targetContent The content for the target token to look for in case there could + * be confusion. + * + * @return void + */ + public function testIsArrowFunction($testMarker, $expected, $targetContent = null) + { + $targets = Collections::arrowFunctionTokensBC(); + $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); + $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); + $this->assertSame($expected['is'], $result); + } + + /** + * Test correctly detecting arrow functions. + * + * @dataProvider dataArrowFunction + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected The expected return value for the respective functions. + * @param string $targetContent The content for the target token to look for in case there could + * be confusion. + * + * @return void + */ + public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = 'fn') + { + $targets = Collections::arrowFunctionTokensBC(); + $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); + + // Change from offsets to absolute token positions. + if ($expected['get'] != false) { + foreach ($expected['get'] as $key => $value) { + $expected['get'][$key] += $stackPtr; + } + } + + $result = FunctionDeclarations::getArrowFunctionOpenClose(self::$phpcsFile, $stackPtr); + $this->assertSame($expected['get'], $result); + } + + /** + * Data provider. + * + * @see testIsArrowFunction() For the array format. + * @see testgetArrowFunctionOpenClose() For the array format. + * + * @return array + */ + public function dataArrowFunction() + { + return [ + 'arrow-function-returning-heredoc' => [ + '/* testHeredoc */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 4, + 'scope_closer' => 9, + ], + ], + ], + 'arrow-function-returning-nowdoc' => [ + '/* testNowdoc */', + [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 2, + 'scope_opener' => 4, + 'scope_closer' => 9, + ], + ], + ], + ]; + } +}