-
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
Handle anonymous class attribute #152
Conversation
Looks like the code in patchwork/src/CodeManipulation/Actions/Generic.php Lines 140 to 143 in 27e8ab9
Also, I find that |
Re: the tests - probably a good idea to add some more variations, like multi-line attributes with array parameters + a class multiple attributes attached, as those cases will need to be handled correctly and are, based on experience elsewhere, the ones which will break any "simple" solution. Another thing which should probably be taken into account (but solved separately) is PHP 8.3 readonly anonymous classes, where the |
Tests that anonymous classes with attribute can be handled properly when configuration `new-keyword-redefinable` is set to `true`.
@@ -137,8 +137,8 @@ function injectCodeAfterClassDefinitions($code) | |||
{ | |||
return function(Source $s) use ($code) { | |||
foreach ($s->all(T_CLASS) as $match) { | |||
if ($s->is([T_DOUBLE_COLON, T_NEW], $s->skipBack(Source::junk(), $match))) { | |||
# Not a proper class definition: either ::class syntax or anonymous class | |||
if ($s->is([T_DOUBLE_COLON, T_NEW, RIGHT_SQUARE], $s->skipBack(Source::junk(), $match))) { |
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
#[\Attribute] | |
class SomeAttribute { | |
public function __construct($value) {} | |
} |
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 the class
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.
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.
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, the class
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 a RIGHT_SQUARE
and $s->match()
for that points to a General\ATTRIBUTE
, skipBack
from that General\ATTRIBUTE
and repeat as necessary for more RIGHT_SQUARE
s. Once it finds a non-bracket (or a RIGHT_SQUARE
not matching with a General\ATTRIBUTE
), then look for the T_DOUBLE_COLON
or T_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 between new
and class
, beside attributes:
https://github.com/nikic/PHP-Parser/blob/master/grammar/php.y#L501-L515
Inspecting the grammar [1] in nikic/PHP-Parser confirms that `readonly` is the only possible intervening keyword here. While `final` and `abstract` are also allowed by the grammar, they generate a compile error for anonymous classes and therefore need not concern us. [1] https://github.com/nikic/PHP-Parser/blob/master/grammar/php.y#L501-L515.
…ss|readonly|#[...])`
@romm, could you run this PR's branch with your intended code base, as an end-to-end test of sorts, and report here? Just to make sure that no other bugs show up. |
Hi @antecedent, just tried the patch on my code base and it works like a charm. I detected another issue regarding private constructors, but it seems to be a completely different problem, I'll investigate on it. Thanks! EDIT: that private constructor thing was an issue on my end, so no worries! |
Hi, first of all thanks for your work, I didn't know about this library and it could be of great use for a test suite in a project of mine.
I ran into the following issue: when an anonymous class uses a PHP 8 attribute, Patchwork crashes.
I'm adding a failing test to this PR, I currently have no idea where to look to fix this, I'd be glad to help if someone gives me a hint. 🙂
Have a good day!