Skip to content
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

phpcs hangs when using arrow functions that return heredoc #2926

Closed
bcremer opened this issue Apr 2, 2020 · 1 comment
Closed

phpcs hangs when using arrow functions that return heredoc #2926

bcremer opened this issue Apr 2, 2020 · 1 comment

Comments

@bcremer
Copy link

bcremer commented Apr 2, 2020

The following combination of arrow function and heredoc will lead to an endless loop:

fn () => <<<HTML
foo
HTML;

Steps to reproduce:

curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar

cat <<EOT >> repro.php
<?php
fn () => <<<HTML
foo
HTML;
EOT

php -l repro.php 
No syntax errors detected in repro.php

$ php phpcs.phar -v repro.php  
Registering sniffs in the PEAR standard... DONE (28 sniffs registered)
Creating file list... DONE (1 files in queue)
Changing into directory /tmp/repro
Processing repro.php 

This will run infinitely.

Full log

This also happens with the current master branch commit 7c406b75a4e53a50aa1eba2d3dda28e3d55f9cfe.

Following the very verbose output of 7c406b75a4e53a50aa1eba2d3dda28e3d55f9cfe:

$ ./PHP_CodeSniffer/bin/phpcs -vvv repro.php
Processing ruleset /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/ruleset.xml
	Adding sniff files from /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs directory
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php
	Processing rule "Generic.Functions.FunctionCallArgumentSpacing"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php
	Processing rule "Generic.NamingConventions.UpperCaseConstantName"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php
	Processing rule "Generic.PHP.LowerCaseConstant"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php
	Processing rule "Generic.PHP.DisallowShortOpenTag"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php
	Processing rule "Generic.WhiteSpace.DisallowTabIndent"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php
	Processing rule "Generic.Commenting.DocComment"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/Commenting/DocCommentSniff.php
	Processing rule "Squiz.Commenting.DocCommentAlignment"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php
	Processing rule "Generic.Files.LineLength"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/Files/LineLengthSniff.php
		=> property "lineLimit" set to "85"
		=> property "absoluteLineLimit" set to "0"
	Processing rule "Generic.Files.LineEndings"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/Files/LineEndingsSniff.php
		=> property "eolChar" set to "\n"
	Processing rule "Generic.Functions.FunctionCallArgumentSpacing.TooMuchSpaceAfterComma"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php
		=> severity set to 0
	Processing rule "Generic.ControlStructures.InlineControlStructure"
		=> /tmp/repro/PHP_CodeSniffer/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php
		=> property "error" set to "false"
=> Ruleset processing complete; included 28 sniffs and excluded 0
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\WhiteSpace\ScopeIndentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\WhiteSpace\ScopeClosingBraceSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\WhiteSpace\ObjectOperatorIndentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\NamingConventions\ValidVariableNameSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\NamingConventions\ValidFunctionNameSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\NamingConventions\ValidClassNameSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionDeclarationSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionCallSignatureSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Formatting\MultiLineAssignmentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Files\IncludingFileSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\ControlStructures\MultiLineConditionSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\ControlStructures\ControlSignatureSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Commenting\InlineCommentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Commenting\FunctionCommentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Commenting\FileCommentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Commenting\ClassCommentSniff
Registered PHP_CodeSniffer\Standards\PEAR\Sniffs\Classes\ClassDeclarationSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\Functions\FunctionCallArgumentSpacingSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\UpperCaseConstantNameSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseConstantSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\DisallowShortOpenTagSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\DisallowTabIndentSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\Commenting\DocCommentSniff
Registered PHP_CodeSniffer\Standards\Squiz\Sniffs\Commenting\DocCommentAlignmentSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineEndingsSniff
Registered PHP_CodeSniffer\Standards\Generic\Sniffs\ControlStructures\InlineControlStructureSniff
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_DO => do
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_CURLY_BRACKET => {
	Process token [4]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token [2]: T_WHILE => while
	Process token [3]: T_WHITESPACE => ·
	Process token  4 : T_OPEN_PARENTHESIS => (
	Process token [5]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token  1 : T_SEMICOLON => ;
	Process token [2]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHILE => while
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_PARENTHESIS => (
	Process token [4]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token  2 : T_OPEN_CURLY_BRACKET => {
	Process token [3]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_FOR => for
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_PARENTHESIS => (
	Process token [4]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token  2 : T_OPEN_CURLY_BRACKET => {
	Process token [3]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_IF => if
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_PARENTHESIS => (
	Process token [4]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token  2 : T_OPEN_CURLY_BRACKET => {
	Process token [3]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_FOREACH => foreach
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_PARENTHESIS => (
	Process token [4]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token  2 : T_OPEN_CURLY_BRACKET => {
	Process token [3]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token  1 : T_CLOSE_CURLY_BRACKET => }
	Process token [2]: T_WHITESPACE => ·
	Process token [3]: T_ELSE => else
	Process token [4]: T_WHITESPACE => ·
	Process token [5]: T_IF => if
	Process token [6]: T_WHITESPACE => ·
	Process token  7 : T_OPEN_PARENTHESIS => (
	Process token [8]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token  2 : T_OPEN_CURLY_BRACKET => {
	Process token [3]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token  1 : T_CLOSE_CURLY_BRACKET => }
	Process token [2]: T_WHITESPACE => ·
	Process token [3]: T_ELSEIF => elseif
	Process token [4]: T_WHITESPACE => ·
	Process token  5 : T_OPEN_PARENTHESIS => (
	Process token [6]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_WHITESPACE => ·
	Process token  2 : T_OPEN_CURLY_BRACKET => {
	Process token [3]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token  1 : T_CLOSE_CURLY_BRACKET => }
	Process token [2]: T_WHITESPACE => ·
	Process token [3]: T_ELSE => else
	Process token [4]: T_WHITESPACE => ·
	Process token  5 : T_OPEN_CURLY_BRACKET => {
	Process token [6]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php·
	Process token [1]: T_DO => do
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_CURLY_BRACKET => {
	Process token [4]: T_CLOSE_TAG => ?>
	*** END PHP TOKENIZING ***
Creating file list... DONE (1 files in queue)
Changing into directory /tmp/repro
Processing repro.php 
	*** START PHP TOKENIZING ***
	Process token [0]: T_OPEN_TAG => <?php\n
	Process token [1]: T_FN => fn
	Process token [2]: T_WHITESPACE => ·
	Process token  3 : T_OPEN_PARENTHESIS => (
	Process token  4 : T_CLOSE_PARENTHESIS => )
	Process token [5]: T_WHITESPACE => ·
	Process token [6]: T_DOUBLE_ARROW => =>
	Process token [7]: T_WHITESPACE => ·
	Process token [8]: T_START_HEREDOC => <<<HTML\n
	Process token  11 : T_SEMICOLON => ;
	Process token [12]: T_WHITESPACE => \n
	*** END PHP TOKENIZING ***
	*** START TOKEN MAP ***
	=> Found unowned parenthesis opener at 3
	=> Found unowned parenthesis closer at 4 for 3
	*** END TOKEN MAP ***
	*** START SCOPE MAP ***
	Start scope map at 8:T_START_HEREDOC => <<<HTML\n
	=> Begin scope map recursion at token 8 with depth 1
	Process token 9 on line 3 [opener:8;]: T_HEREDOC => foo\n
	Process token 10 on line 4 [opener:8;]: T_END_HEREDOC => HTML
	=> Found scope closer (10:T_END_HEREDOC) for 8:T_START_HEREDOC
	*** END SCOPE MAP ***
	*** START LEVEL MAP ***
	Process token 0 on line 1 [col:1;len:5;lvl:0;]: T_OPEN_TAG => <?php\n
	Process token 1 on line 2 [col:1;len:2;lvl:0;]: T_FN => fn
	Process token 2 on line 2 [col:3;len:1;lvl:0;]: T_WHITESPACE => ·
	Process token 3 on line 2 [col:4;len:1;lvl:0;]: T_OPEN_PARENTHESIS => (
	Process token 4 on line 2 [col:5;len:1;lvl:0;]: T_CLOSE_PARENTHESIS => )
	Process token 5 on line 2 [col:6;len:1;lvl:0;]: T_WHITESPACE => ·
	Process token 6 on line 2 [col:7;len:2;lvl:0;]: T_DOUBLE_ARROW => =>
	Process token 7 on line 2 [col:9;len:1;lvl:0;]: T_WHITESPACE => ·
	Process token 8 on line 2 [col:10;len:7;lvl:0;]: T_START_HEREDOC => <<<HTML\n
	=> Found scope opener for 8:T_START_HEREDOC
		* level increased *
		* token 8:T_START_HEREDOC added to conditions array *
		Process token 9 on line 3 [col:1;len:3;lvl:1;conds;T_START_HEREDOC;]: T_HEREDOC => foo\n
		Process token 10 on line 4 [col:1;len:4;lvl:1;conds;T_START_HEREDOC;]: T_END_HEREDOC => HTML
		=> Found scope closer for 8:T_START_HEREDOC
		* token T_START_HEREDOC removed from conditions array *
		* level decreased *
	Process token 11 on line 4 [col:5;len:1;lvl:0;]: T_SEMICOLON => ;
	Process token 12 on line 4 [col:6;len:0;lvl:0;]: T_WHITESPACE => \n
	*** END LEVEL MAP ***
	*** START ADDITIONAL PHP PROCESSING ***
@gsherwood gsherwood added this to Idea Bank in PHPCS v3 Development via automation May 1, 2020
@gsherwood gsherwood added this to the 3.5.6 milestone May 1, 2020
@gsherwood
Copy link
Member

Thanks for the very clear bug report and reproduction steps. The fix for this will be released in 3.5.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
PHPCS v3 Development
Ready for Release
Development

No branches or pull requests

2 participants