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

Make InnerFunctionsSniff detect functions inside closures #3807

Merged
merged 4 commits into from
Jul 11, 2023

Conversation

Daimona
Copy link
Contributor

@Daimona Daimona commented Apr 19, 2023

Fixes #3806

Copy link
Contributor

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jrfnl
Copy link
Contributor

jrfnl commented Apr 19, 2023

I agree this is a good change, but looking at this sniff now, I see more things wrong with it.

@Daimona Would you be willing to make some additional fixes ?

Additional things which I believe should be addressed:

  1. There is redundant code (the check for =). This is due to in the older day closures being tokenized as T_FUNCTION. That code will never be matched anymore now.
  2. The part where it checks for methods in anonymous classes should probably be expanded to check for all OO structures.
    See: https://3v4l.org/c2Cbn
  3. As more checking of the conditions is now needed, the sniff should probably check the conditions array itself instead of using getCondition().

Does that make sense ?

@Daimona
Copy link
Contributor Author

Daimona commented Apr 19, 2023

  1. There is redundant code (the check for =). This is due to in the older day closures being tokenized as T_FUNCTION. That code will never be matched anymore now.

Makes sense to me! In fact, I was a bit puzzled by that check given the existence of T_CLOSURE (that's not listed in register()).

I agree with the rest as well. I've updated my PR.

Copy link
Contributor

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making these updates @Daimona !

Looking good.

I wonder if the two loops walking the $conditions array can be combined ?

I'm thinking that logic like this may work (very much pseudo-code):

// Reverse the conditions array
foreach () {
    if ($condition === T_FUNCTION || $condition === T_CLOSURE) {
        break; // Error.
    }

    if (isset(Tokens::$ooScopeToken[$condition])) {
        return; // Found OO structure before function/closure, so this is an OO method.
    }
}

src/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php Outdated Show resolved Hide resolved
@jrfnl
Copy link
Contributor

jrfnl commented Apr 19, 2023

Extra code sample you may want to add to the tests (would currently not be detected/false negative):

function foo() {
    if (class_exists('Bar') === false) {
        class Bar {
            function foo() {
                function innerFunction() {} // Error.
            }
        }
    }
}

@Daimona
Copy link
Contributor Author

Daimona commented Apr 19, 2023

I wonder if the two loops walking the $conditions array can be combined ?

I wanted to use separate loops so that we can bail out earlier if it's not a nested function. However, on second though that's simply untrue -- we'd loop through the whole array of conditions in the common case without nested functions. And I guess reversing the array of conditions is not terribly expensive, either, so I'm going to merge the loops, and make all the other suggested changes.

Copy link
Contributor

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🎉

Thanks for working with me to get this sniff into shape!

@jrfnl jrfnl added this to the 3.8.0 milestone Jun 21, 2023
@jrfnl
Copy link
Contributor

jrfnl commented Jul 11, 2023

@Daimona I'm going to merge this PR. The changelog normally contains the full name of the contributor. Would you mind sharing yours ?

@Daimona
Copy link
Contributor Author

Daimona commented Jul 11, 2023

@Daimona I'm going to merge this PR. The changelog normally contains the full name of the contributor. Would you mind sharing yours ?

Hi :) I don't use my real name online; at least not in connection with this username. Would it be possible to just credit me as "Daimona"?

@jrfnl
Copy link
Contributor

jrfnl commented Jul 11, 2023

Hi :) I don't use my real name online; at least not in connection with this username. Would it be possible to just credit me as "Daimona"?

Absolutely! Just wanted to give you the chance, but only if you want it.

@jrfnl jrfnl merged commit 1701786 into squizlabs:master Jul 11, 2023
jrfnl added a commit that referenced this pull request Jul 11, 2023
jrfnl pushed a commit that referenced this pull request Jul 11, 2023
@jrfnl
Copy link
Contributor

jrfnl commented Dec 8, 2023

FYI: this fix is included in today's PHP_CodeSniffer 3.8.0 release.

As per #3932, development on PHP_CodeSniffer will continue in the PHPCSStandards/PHP_CodeSniffer repository. If you want to stay informed, you may want to start "watching" that repo (or watching releases from that repo).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

InnerFunctionsSniff should flag functions defined inside closures
2 participants