-
-
Notifications
You must be signed in to change notification settings - Fork 492
AbstractFunctionParameterSniff: fix first class callables and function imports #2518
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
AbstractFunctionParameterSniff: fix first class callables and function imports #2518
Conversation
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.
@rodrigoprimo Thank you for working on this.
I've verified the tests cover the change. ✔️,
Some remarks about the tests:
- Please do set a valid value for
old_text_domain
as currently the sniff would throw unrelated errors if it would be triggered. - Please remember to reset the changed properties to their default value at the end of a test case file as otherwise it can influence other tests.
- Lastly, I see no reason for the tests to have their own case file. AFAICS these can just be added to the
3
or4
file ?
As for the new method.... I believe the code in the is_targetted_token()
can be simplified.
I also think the code as-is, is broken as it doesn't account for variable unpacking.
While the sniff used for testing wouldn't necessarily be able to act on that, it is not for the abstract to disregard variable unpacking outright.
Want to have another think about this yourself or would you like me to give you some clues ?
e1fe56a
to
bc445b0
Compare
Thanks for the review, @jrfnl!
I moved the tests to
I made some minor simplifications, but I have a feeling you have something else in mind that I could not find.
I changed the code to disregard only first class callables and not variable unpacking. Could you please take another look? |
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.
@rodrigoprimo Had another look. Second and third commit are useful, the fourth is definitely not what I had in mind.
Hint: Have a look at the "function import" check code - in the original method in the other abstract, it is important that it is determined properly whether something is a function import statement. For this method, however, we don't need to determine whether it is, just that it isn't a function call (which is much simpler to do and would use code which the first class callable check needs as well anyway).
I'm also missing a test safeguarding that the abstract will not disregard variable unpacking as if it were a first class callable.
Thanks again, @jrfnl.
I believe now I have implemented something in line with what you hinted. I changed the first check in the method to only verify if the token after the function name is not an opening parenthesis instead of checking the previous and next tokens to ensure it is not a function import.
I added it now. At first, I didn't include this test as it triggers a false positive in the sniff that must be addressed separately. But it makes sense to have it to ensure that the changes to the abstract behave correctly. I will create a separate issue to check if the sniffs that extend this abstract need to be updated to handle variable unpacking correctly. |
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.
@rodrigoprimo Functionally, all is good now.
Code-style wise, I'm not keen on the implicit comparisons in the code, like if ($firstNonEmpty)
, as they are very bug prone.
They will work in this case as you're looking for findNext()
, but can easily break on a findPrevious()
where the result can be a perfectly valid 0
.
I'd much prefer if the conditions are made explicit - if ($firstNonEmpty !== false)
- to make it clearer what is actually being checked and to stabilize the code.
On that note: the check for T_OPEN_PARENTHESIS
does not check against $next
being falsy, while the other two findNext()
calls do.
Question: are the "falsy" checks even necessary ? Keep in mind that these are function names which have already been validated by the parent::is_targetted_token()
function...
I also think the tests could be improved a little more too as there are a number of things not tested now, but it could be argued that that should be left for the abstract in PHPCSUtils.
Situations which the code currently handles correctly, but which are not currently safeguarded by the tests:
- Live coding (those implicit conditions) x 2.
- Whitespace and comments in unconventional places, like between the function name and the open parenthesis, between the open parenthesis and the
...
, between the...
and the close parenthesis and/or variable.
Thanks for checking the changes, @jrfnl!
Good point, should be fixed now.
I opted not to include a check for On a somewhat related note, a function name followed by an opening parenthesis with nothing after it, for example
Yeah, my original idea was precisely to leave adding more tests to the abstract in PHPCSUtils. But I went ahead and added the tests that you suggested.
Not sure if I understand the times two part. I added the live coding tests that I think are relevant. Please let me know if I'm still missing some live coding tests. |
👍🏻
👍🏻
I'd be fine with changing that behaviour and I believe this PR is the right place to do it. To be honest, I thought the abstract already checked for open + close parenthesis, but I may have been confused with the abstract in PHPCompatibility. (👈🏻 This is why these abstracts should move to PHPCSUtils 😉 ) Do note that the Having said that, I agree with you that it would be better for the abstract to not act on unfinished function calls altogether.
Looks like the tests I had in mind were all added, so all good. Only thing missing is the Looks like previous tests related to this abstract were added to the |
588ab72
to
a6afb79
Compare
@jrfnl, I went ahead and pushed a new commit to make the abstract ignore unfinished function calls.
Done |
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.
@rodrigoprimo Thanks for working on this. LGTM, let's get this merged!
@rodrigoprimo Would you like to clean up the commits so it's fully ready for merge ? |
…n imports The `AbstractFunctionParameterSniff` class was incorrectly flagging first class callables and function imports as a function call without parameters. This commit fixes this behavior by introducing the `AbstractFunctionParameterSniff::is_targetted_token()` method. This method calls the parent method and then performs two additional checks to make sniffs extending this class ignore first class callables and function imports. Since there are no tests for the abstract classes and the plan is to replace those classes with similar PHPCSUtils classes, I opted to add a few tests to the `I18nTextDomainFixer` tests that generate false positives before the changes implemented in this commit.
…alls Before this commit, the `AbstractFunctionParameterSniff` class would incorrectly treat an unfinished function call (missing closing parenthesis) as a function call without parameters. This behavior is now changed and the class will bail early when the closing parenthesis is missing and assume it is a syntax error or live coding.
a6afb79
to
25f1235
Compare
@jrfnl, sure! I combined all the commits related to changes to ensure that the abstract class does not treat first class callable and function imports as a function call into the first commit, and left the commit to bail early if the function call is unfinished alone. |
@rodrigoprimo Excellent! Thanks. |
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.
Left just one minor question.
@rodrigoprimo What kind of feedback are you expecting ? Or what are you expecting feedback on ? |
@jrfnl, that the issue that I created is clear and correctly describes what needs to be done. |
Ah. Well, seems clear enough to me. Could do with a code sample of the syntax the sniffs should be tested against, but other than that, all good. |
I just created the PHPCompatiblity issue: PHPCompatibility/PHPCompatibility#1799
I will add a few code samples to both issues. |
The
AbstractFunctionParameterSniff
class was incorrectly flagging first class callables and function imports as a function call without parameters. This PR fixes this behavior by introducing theAbstractFunctionParameterSniff::is_targetted_token()
method. This method calls the parent method and then performs two additional checks to make sniffs extending this class ignore first class callables and function imports.Since there are no tests for the abstract classes and the plan is to replace those classes with similar PHPCSUtils classes, I opted to add a few tests to the
I18nTextDomainFixer
tests that generate false positives before the changes implemented in this PR.Update 24/02/2025: after discussing this during the review process (see #2518 (comment)), this PR now also changes how the
AbstractFunctionParameterSniff
class handles unfinished function calls (when the closing parenthesis is missing). Now, it will ignore them as syntax error or live coding.