False positive on "Avoid unused private methods"
llaville opened this issue · comments
- PHPMD version: 2.15.0snapshot202312110823
- PHP Version: 8.2.15
- Installation type: (phar file/ composer) PHAR (with deprecated errors : read my comment)
- Operating System / Distribution & Version: Linux Ubuntu 22..04.3 LTS
Current Behavior
Report a violation about a private method that is called as callback on an array_filter
function.
Expected Behavior
Do not report violation on such context
Steps To Reproduce:
When running command php phpmd.phar src ansi unusedcode
on source code of https://github.com/composer-unused/symbol-parser/tree/0.2.2, I got false positive
FILE: /shared/backups/forks/symbol-parser/src/Symbol/Loader/FileSymbolLoader.php
--------------------------------------------------------------------------------
139 | VIOLATION | Avoid unused private methods such as 'filterExistingDir'.
FILE: /shared/backups/forks/symbol-parser/src/Symbol/Loader/PsrSymbolLoader.php
-------------------------------------------------------------------------------
22 | VIOLATION | Avoid unused local variables such as '$dir'.
Found 2 violations and 0 errors in 568ms
NOTE I've removed deprecated error displayed to have a better readability of report !
On report, 139 | VIOLATION | Avoid unused private methods such as 'filterExistingDir'.
is false because private method is used by this call => https://github.com/composer-unused/symbol-parser/blob/0.2.2/src/Symbol/Loader/FileSymbolLoader.php#L53
Checks before submitting
- Be sure that there isn't already an issue about this. See: Issues list
- Be sure that there isn't already a pull request about this. See: Pull requests
- I have added every step to reproduce the bug.
- If possible I added relevant code examples.
- This issue is about 1 bug and nothing more.
- The issue has a descriptive title. For example: "JSON rendering failed on Windows for filenames with space".
I know it's doesn't solve the issue in phpmd, but could you try using an arrow function as a workaround and see if that works for your code base?
$sourceFolders = array_filter($sourceFolders, fn (string $dir): bool => $this->filterExistingDir($dir));
In 8.1 you could use a first-class closure:
$sourceFolders = array_filter($sourceFolders, $this->filterExistingDir(...));
@AJenbo I agree with you : there are always alternative to write code in another way.
But if I wrote this report that is just to share and keep PHPMD team aware of false violation reporting !
$sourceFolders = array_filter($sourceFolders, fn (string $dir): bool => $this->filterExistingDir($dir));
Feature available since PHP 7.4 ( https://www.php.net/manual/en/functions.arrow.php )
And repo https://github.com/composer-unused/symbol-parser code base require at least PHP 7.4 to run ;-)
Yeah I made sure to check your repo before suggesting it ;)
It's not my repo. I'm just a contributor !
Sorry
While $this->filterExistingDir()
is straightforward to recognize as a call of the private method filterExistingDir
(with current PDepend parser abilities), recognizing that [$this, 'filterExistingDir']
is also a call to private method is more tricky. It depends on where it got passed (if passed to a callable
parameter or put in a value that is later triggered with ()
or with call_user_func()
or itself passed to a callable
parameter, etc.) so we would have to track it potentially very far to actually know that it indeed represent a callable
.
We could not check where it goes and in the doubt assume that an array of 1 element being $this
and another element being a string
(such as [$this, 'filterExistingDir']
) is very likely to be used as a callable
and so check the string statically and not raise the violation.
We would still have issue as this array can be constructed dynamically, and also the string can be obtained by concatenation or from a non-static value.
So with some effort we would obtain a smarter result but still with false positives and false negatives.
NOTE I've removed deprecated error displayed to have a better readability of report !
Deprecations are expected to happen when running the PHAR version of PHPMD (because it supports all versions of PHP from 5.3)
You can use:
php -d error_reporting=8191 phpmd.phar source text rules.xml
Using composer install you won't have any deprecation raised.
For what it's worth PHPStan's latest updates sees [0 => object, 1 => 'method_name']
as a callable, even if it doesn't see it used. I think this is a fair assumption as it is indeed callable. It would require that we can see what object it is, and can use the string to look for existing methods on that class. Stan is also able to track the construction of arrays that we are not able to.
Cool so #1068 is the way to go. 👍
First thing first recognize $this
as an easy win which likely represent majority of the use cases.
Then we can try to identify clone $this
, new self
and the like as best-effort (we can detect in the body of the current method, but if it's passed argument or dynamically transformed value, we'll be beaten, though it might not be a big concern as those should not happen in clean code)