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

Generic/ConstructorName: fix bug with nested anonymous classes and more #2182

Merged

Conversation

jrfnl
Copy link
Contributor

@jrfnl jrfnl commented Oct 6, 2018

Based on the bug report and test case in issue #2178, I've had a look at this sniff.

Turns out the processTokensWithinScope() method gets called for each whitelisted scope a T_FUNCTION token exists in.

In effect, this means that the first time it gets called for the nested() method, it is because it is within the scope of the Nested class, the second time the function gets called, it is for the method being in the scope of the anonymous class.

The fix I've now applied checks that the scope for which the method is called is actually the deepest scope first and bows out if it's not. This fixes the false positive.

Additionally, the loadFunctionNamesInScope() method would examine every token within the class and the resulting function list would therefore include the names of functions which were nested.
This would lead to false negatives as a __construct() method in a nested class would be regarded as the __construct() method of the higher level class and the expected error would not be thrown.

I've fixed this by having the loadFunctionNamesInScope() method skip to the end of a function after adding the function name to the list, which effectively will prevent the names of nested functions from getting into the list.
This should also make the method more efficient as it now examines a lot less tokens.

Additional notes:

  • Class and method names in PHP are case _in_sensitive. While the sniff tried to take that into account by using strcasecmp(), the in_array() check and the check for the extended parent class name were not done in a case-insensitive manner leading - again - to incorrect results.
    This has now been fixed by lowercasing both the class name as well as all function names before comparing them.
  • Use strict comparison for in_array() to prevent issues with type juggling.
  • Includes minor fix to an existing unit test - the sniff logic contains a "caching" mechanism for the list of function names gathered which is based on the name of the class.
    As the name of the class on line 32 was the same as the name of the class for the preceding unit test case, the function name list did not get refreshed and therefore the unit test wasn't testing things correctly.

Includes unit tests for all fixes.

Fixes #2178

Based on the bug report and test case in issue 2178, I've had a look at this sniff.
Turns out the `processTokensWithinScope()` method gets called for each whitelisted scope a `T_FUNCTION` token exists in.

In effect, this means that the first time it gets called for the `nested()` method, it is because it is within the scope of the `Nested` class, the second time the function gets called, it is for the method being in the scope of the anonymous class.

The fix I've now applied checks that the scope for which the method is called is actually the deepest scope first and bows out if it's not. This fixes the false positive.

Additionally, the `loadFunctionNamesInScope()` method would examine every token within the class and the resulting function list would therefore include the names of functions which were nested.
This would lead to false negatives as a `__construct()` method in a nested class would be regarded as the `__construct()` method of the higher level class and the expected error would not be thrown.

I've fixes this by having the `loadFunctionNamesInScope()` method skip to the end of a function after adding the function name to the list, which effectively will prevent the names of nested functions from getting into the list.
This should also make the method more efficient as it now examines a lot less tokens.

Additional notes:
* Class and method names in PHP are case _in_sensitive. While the sniff tried to take that into account by using `strcasecmp()`, the `in_array()` check and the check for the extended parent class name were *not* done in a case-insensitive manner leading - again - to incorrect results.
     This has now been fixed by lowercasing both the class name as well as all function names before comparing them.
* Use strict comparison for `in_array()` to prevent issues with type juggling.
* Includes minor fix to an existing unit test - the sniff logic contains a "caching" mechanism for the list of function names gathered which is based on the name of the class.
    As the name of the class on line 32 was the same as the name of the class for the preceding unit test case, the function name list did not get refreshed and therefore the unit test wasn't testing things correctly.

Includes unit tests for all fixes.

Fixes 2178
@gsherwood
Copy link
Member

If you weren't sending PRs, nothing would get done. Thank you!

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

Successfully merging this pull request may close these issues.

Generic.NamingConventions.ConstructorName matches methods in anon classes with same name as containing class
2 participants