-
Notifications
You must be signed in to change notification settings - Fork 41
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
Handle anonymous class attribute #152
Merged
antecedent
merged 10 commits into
antecedent:master
from
romm:fix/anonymous-class-attribute
Feb 6, 2024
Merged
Changes from 5 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
27e8ab9
Add failing test for anonymous class attribute
romm c8a47ac
Add more cases in anonymous class attribute test
romm 49f8fff
Fix handling of anonymous class with attribute
romm 368f49b
Add failing test for redefinition of new anonymous class with attribute
romm 28c1464
Fix handling redefinition of new for anonymous class with attribute
romm 855dc3b
Look for T_STRING on the right side of T_CLASS
antecedent 88c50ac
Look for LEFT_ROUND | LEFT_CURLY | T_EXTENDS | T_IMPLEMENTS instead
antecedent 3615e89
When searching for `new class`, include `new readonly class` as well
antecedent 2abd509
Add a version-proof T_READONLY
antecedent bc7d1c8
When searching for `new class` (take 2), search instead for `new (cla…
antecedent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--TEST-- | ||
Attribute declared in anonymous class | ||
|
||
--SKIPIF-- | ||
<?php version_compare(PHP_VERSION, "8.0", ">=") | ||
or die("skip because attributes are only available since PHP 8.0") ?> | ||
|
||
--FILE-- | ||
<?php | ||
|
||
error_reporting(E_ALL | E_STRICT); | ||
|
||
require __DIR__ . "/../Patchwork.php"; | ||
require __DIR__ . "/includes/AnonymousClassAttribute.php"; | ||
|
||
?> | ||
===DONE=== | ||
|
||
--EXPECT-- | ||
===DONE=== |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
#[\Attribute] | ||
class SomeAttribute { | ||
public function __construct($value) {} | ||
} | ||
|
||
// Simple attribute | ||
new #[SomeAttribute('foo')] class {}; | ||
|
||
// Several attributes | ||
new #[SomeAttribute('foo')] #[SomeAttribute('bar')] class {}; | ||
|
||
// Attribute with argument on several lines | ||
new #[SomeAttribute([ | ||
'foo', | ||
'bar', | ||
])] class {}; |
22 changes: 22 additions & 0 deletions
22
tests/redefinition-new-anonymous-class-with-attribute.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--TEST-- | ||
Redefinition of new in anonymous class with attribute | ||
|
||
--SKIPIF-- | ||
<?php version_compare(PHP_VERSION, "8.0", ">=") | ||
or die("skip because attributes are only available since PHP 8.0") ?> | ||
|
||
--FILE-- | ||
<?php | ||
|
||
error_reporting(E_ALL | E_STRICT); | ||
|
||
$_SERVER['PHP_SELF'] = __FILE__; | ||
|
||
require __DIR__ . "/../Patchwork.php"; | ||
require __DIR__ . "/includes/AnonymousClassAttribute.php"; | ||
|
||
?> | ||
===DONE=== | ||
|
||
--EXPECT-- | ||
===DONE=== |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This incorrectly excludes injecting code after
patchwork/tests/includes/AnonymousClassAttribute.php
Lines 3 to 6 in 28c1464
A test for that might have to actually call
Patchwork\CodeManipulation\transformString()
and examine the output rather than just seeing that there's no fatal error raised.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well observed. To be honest I have no clue how to fix the issue, how to detect that a class with attribute is anonymous or not. Do you have any idea on how to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that all named classes have a T_STRING token (the name) following the
class
token. This, however, only comes from my intuition for the time being, and could be wrong. But if it is correct, then we could get around this issue by inspecting the token on the right side of theclass
token, not the left side.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends on how the tokenizer is run. Looks like it is run with the
TOKEN_PARSE
$flag
, in which case probably yes, though results from running the tokenizer with that flag vary depending on the PHP version (then again, that is the case for token streams anyway).In PHPCS, to determine whether the
class
keyword is an anonymous class or a named class, we check if the next non-empty token is one of the following, if it is, theclass
keyword is marked as an anonymous class:(
(open parenthesis){
(open curly)T_EXTENDS
T_IMPLEMENTS
Hope that helps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally what I was thinking of doing was to
$pos = $s->skipBack(Source::junk(), $match)
, then if it's pointing at aRIGHT_SQUARE
and$s->match()
for that points to aGeneral\ATTRIBUTE
,skipBack
from thatGeneral\ATTRIBUTE
and repeat as necessary for moreRIGHT_SQUARE
s. Once it finds a non-bracket (or aRIGHT_SQUARE
not matching with aGeneral\ATTRIBUTE
), then look for theT_DOUBLE_COLON
orT_NEW
.Although I like @jrfnl 's idea too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took @jrfnl 's suggestion. Both the last one, and the previous one about
readonly
. T_READONLY really seems to be the only token that could intervene betweennew
andclass
, beside attributes:https://github.com/nikic/PHP-Parser/blob/master/grammar/php.y#L501-L515