Problem/Motivation
I'm finding more and more incomplete or wrong type hints with PHPStan. We are running PHPStan on our private code base, but it complains about type mismatches due to Drupal core not being documented correctly.
Example:
Parameter #1 $label of method Drupal\Core\TypedData\DataDefinition::setLabel() expects string, Drupal\Core\StringTranslation\TranslatableMarkup given.
Steps to reproduce
Run PHPStan with at least level 5 on a code base that makes use of a lot of core APIs.
Proposed resolution
Start a PHPStan initiative to run a phpstan.neon config on Drupal core itself to figure out problems. We can enable PHPStan runs on the testbot by modifying drupalci.yml and adding a step. That way we prevent regressions for any Drupal core changes in the future.
- commit a patch (this issue) with ignores and a baseline that can enable running PHPStan level 0 and prevent further level-0 issues to enter the codebase
- in this issue, keep to a minimum other code changes - i.e. only those without which PHPStan execution would crash
- once committed, open followups to clean baseline and ignores to level up the existing codebase to level 0
- once above done, repeat the same for level 1 and so forth
Dependency evaluations
Dependency evaluation for PHPStan
Maintainership: Very frequent releases. 55 million downloads from packagist. One of the main static analysis tools for PHP.
Security policies: See https://github.com/phpstan/phpstan/blob/260513fc8d06403dfe82e7665262ca1c.... This is a dev tool and will not be present on production. There has not been a security issue raised against the project.
Expected release and support cycles: Frequent. Version 1.0 was released in Nov 2021. We are already on 1.3.3
Dependency evaluation for phpstan/extension-installer
Maintainership: Part of the PHPStan package.
Security policies: None. This is a dev tool and will not be present on production. This is a composer plugin to make it easy to use libraries which add PHPStan rules.
Expected release and support cycles: Likely to change only when to composer changes.
Dependency evaluation for mglaman/phpstan-drupal
Maintainership: Maintained by Matt Glaman who has worked on Drupal for many years.
Security policies: See https://github.com/mglaman/phpstan-drupal/blob/main/.github/SECURITY.md. This is a dev tool and will not be present on production.
Expected release and support cycles: Will change when an upstream change in PHPStan forces it to. Likely to change as more rules are added because of usage by core :)
Dependency evaluation for webflo/drupal-finder
Maintainership: Maintained by webflo who has worked on Drupal for many years.
Security policies: None. This is a dev tool and will not be present on production. It is used by Drush so it present on thousands of Drupal installs already.
Expected release and support cycles: Only likely to change if core changes it's directory structure.
Remaining tasks
1) One ignored error in phpstan.neon
+++ b/core/phpstan.neon.dist
@@ -0,0 +1,36 @@
+ # @todo files below need to be excluded as they prevent baseline generation.
+ # Fixing them is a priority.
+ - modules/link/tests/src/Kernel/LinkItemTest.php
+
would be nice to be fixed before commit, but it's not a blocker.
It's currently being looked at #3254966: PHPStan error LinkItemTest and upstream at https://github.com/mglaman/phpstan-drupal/pull/279, https://github.com/mglaman/phpstan-drupal/issues/228, https://github.com/phpstan/phpstan/issues/6231. Once solved we will need updating to a new version of both phpstan/phpstan and mglaman/phpstan-drupal.
2) PHPStan recommends to always run analysis full scope - a result cache is implemented for that purpose, see https://phpstan.org/user-guide/result-cache
PHPStan caches the result of the analysis so the subsequent runs are much faster. You should always analyse the whole project - the list of paths passed to the analyse command should be the same to take advantage of the result cache.
However, it may be hard to do in DrupalCI.
User interface changes
None
API changes
None
Data model changes
None
Release notes snippet
The <a href="https://www.drupal.org/node/3258232">PHPStan static analysis library has been added to Drupal core</a> and is run against all core patches and merge requests.
Comment | File | Size | Author |
---|---|---|---|
#192 | 3178534-191.patch | 75.37 KB | alexpott |
| |||
#192 | pseudo-interdiff.txt | 2.72 KB | alexpott |
#182 | 3178534-182.patch | 74.73 KB | alexpott |
#182 | 163-182-interdiff.txt | 20.18 KB | alexpott |
Issue fork drupal-3178534
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
klausiHere is the batch of current problems I run into.
Comment #3
alexpottThese changes are tricky. Because I think what we want here is to use the PHP 8 pseudo class stringable. I think PHPStan should recognise when you are passing an object that implements __toString() and think this is okay - or at least make that behaviour configurable.
Comment #5
klausiMaybe it is a good idea to start with a phpstan.neon config file in Drupal core that we can run at least manually? Created that in the merge request for this issue, looks like this for now:
I fixed 2 minor issues, but then I think PHPStan found the first real bug in ProxyBuilder:
Note that I only enabled PHPStan on a fraction of Drupal core's code base on level 1 and I already get 60+ errors here. This will be a monumental effort to get Drupal core level 1 compliant and there are 8 PHPStan levels :-D
Comment #6
alexpottOne thing that PHPStan allows you to do that is neat is set a baseline. So we could start with that and then work towards fix all the errors in the baseline. See https://phpstan.org/user-guide/baseline
Comment #7
klausiCreated #3186626: Second parameter of ProxyBuilder::build() is never used and broken for the ProxyBuilder bug.
Comment #8
klausi@alexpott: the baseline is a good idea, but I don't want to ship a baseline file with several hundred kilobytes of errors with Drupal core. So Instead I would use the reverse approach and add more and more subfolders that pass level 1 to phpstan.neon.
As a first experiment I can try to finish the folder lib/Drupal/Component and see how that goes and if there are any patterns.
Comment #9
klausilib/Drupal/Component done and I think this yielded some nice improvements.
Do we want to do some more folders here in one go? Or do we want to come up with a strategy for splitting this out into sub-issues first?
Change is still small enough I think that we could do 1-3 folders more.
Comment #10
klausiOh wow, I figured out how to run PHPStan on DrupalCI on the first try!
This is nice, we could start with enabled PHPStan checking right away.
Comment #11
alexpottThe automation of this probably should be a follow-up from #3178845: Run same checks as committers do on DrupalCI
Also I've noticed quite a few PHP projects moving away from phpstan and to psalm
Comment #12
klausiWe could also use Psalm, I just found it to be slightly harder to set up for Coder in #3109007: Check Coder with Psalm and it is less popular than PHPStan (Github stars).
I will fix your comment and wait for more feedback before fixing up more core folders.
Comment #13
andypost@klausi thanks for link, it looks less terrible then 2 years ago
Comment #14
klausiTurns out we have indirect test coverage for allowedIfHasPermissions() and there are legitimate use cases to call it with just 1 permission for generic code like in PermissionAccessCheck. So I reverted my last commit.
The code worked by accident because it relied on $permission being defined further above in the foreach loops. That is a bad practice because if that code is ever changed then we get undefined variable behavior. It is also harder to understand where $permission comes from when it is used in the message.
We should really get the variable in the current scope like my original fix did.
Alternatively we could check for count($permissions) === 1 in the beginning of allowedIfHasPermissions() and call allowedIfHasPermission(), but I don't want to change too much just to make the code cleaner here.
Comment #15
klausiUpdated the issue summary with the plan to enable PHPStan testing.
Will modify the merge request to start with the even lower level 0 next.
Comment #16
daffie CreditAttribution: daffie commentedThe testbot is returning with:
See: https://dispatcher.drupalci.org/job/drupal_patches/72429/console
Comment #17
daffie CreditAttribution: daffie commentedWhen I run the command on my local machine I get the following error:
Comment #18
daffie CreditAttribution: daffie commented@klausi: Could you explain why the MR has so many changes in it. When I apply your MR without all the added fixes I only get 5 errors:
Comment #19
klausi@daffie: Good point! I fixed the missing Expression class which is an optional dependency of Drupal core. I just scan the same test dummy as we do during phpunit tests. I also set drupalci.yml to hard fail a test run when PHPstan errors.
Additional changes: I started out in this issue with level 1 checking but then found that there is also level 0 in PHPStan. I did not want to throw away the level 1 fixes here since they are all reasonable and I think we can keep them.
Comment #20
daffie CreditAttribution: daffie commentedI completely understand you and if I where in your position I would like to do the same. Only I think that it is better do do only the things in this issue to make it past level 0 and move the other changes to the followup issue for passing level 1. Sorry :-(
Comment #21
klausiOK, I can do that. Created 2 child issues to not lose any work:
#3190393: Start running PHPStan on Drupal core (level 0 - part 2)
#3190406: Update PHPStan to level 1
Comment #22
klausiReverted all the level 1 changes, now only level 0 changes remain. Makes the merge request quite a bit smaller, so that is good for reviewers. The small subset of Drupal core that we start with here will not disrupt many other core changes and we can focus on the phpstan configuration for this issue.
Comment #23
daffie CreditAttribution: daffie commentedComment #24
klausiThanks for the review daffie, this is ready to be checked again!
Comment #25
daffie CreditAttribution: daffie commented@klausi: Thank you for answering all my questions. PHPStan was new for me. I think we are going to do a lot more PHPStan issues. Do you have any indication how much memory I would need?
It all looks good to me.
For me it is RTBC.
Comment #26
daffie CreditAttribution: daffie commentedComment #27
daffie CreditAttribution: daffie commentedComment #28
alexpottGiven we are adding a new dependency to Drupal we need to complete a dependency evaluation. See https://www.drupal.org/about/core/policies/core-dependencies-policies/co... for the type of table and information we need.
We also need a change record and release note describing the new dependency and how core devs can use it. The new script makes things pretty simple.
Comment #29
andypostIf core will maintain compatibility wiyh phpstan, contrib modules will have less surface to maintain
For example upgrade status could drop few dependencies #3100308: Make Upgrade Status tests Drupal 9 compatible
Comment #30
andypostComment #33
longwaveI couldn't figure out how to rebase the existing MR so I made a new branch and MR. This updates PHPStan to the latest version, adds a composer run command, adds PHPStan to commit-code-check.sh, adds the .profile extension for scanning and skips *.api.php from being scanned.
If I run it on the full lib directory I get an error that I don't know how to resolve:
Child process error (exit code 255): PHP Fatal error: During class fetch: Uncaught PHPStan\Broker\ClassAutoloadingException: Class Drupal\system\ModuleDependencyMessageTrait not found. in
phar:///.../vendor/phpstan/phpstan/phpstan.phar/src/Reflection/Runtime/RuntimeReflectionProvider.php:133
Comment #34
longwaveIn the 9.2.x branch I've merged in the changes from #3190393: Start running PHPStan on Drupal core (level 0 - part 2) as well. If we are to add this to the commit check script we can't do this in two parts, we have to clean all this up in one go. It might be worth spinning some of these changes out into separate issues and committing them first.
Comment #35
longwaveAs there are so many changes in level 0, maybe another way of doing this would be to tackle it as we do with phpcs: enable one rule at a time.
We could run a custom ruleset and fix individual rules in separate issues, that is probably a good way of scoping this anyway?
Comment #36
longwaveThis seems to be because of core/lib/Drupal/Core/Extension/ThemeInstaller.php:
This is core depending on a module, but PHPstan doesn't know how to autoload modules, so it crashes here.
edit: opened #3204220: ModuleDependencyMessageTrait is used by core but belongs to system module
Comment #37
andypostGood catch! I bet there's more places to fix, like usage of core in components
Comment #38
longwave@andypost this is the only case I could find of a module being used from Drupal\Core, and there are only @see references from Drupal\Component to Drupal\Core - no actual dependencies.
Comment #41
longwaveWith the help of @mglaman's
mglaman/phpstan-drupal
package, we can autoload module code correctly, which gives a fuller set of results.The 3178534-third-attempt branch contains only PHPStan and mglaman/phpstan-drupal, with a number of common errors ignored for the time being. This leaves just under 100 errors that seem feasible to fix as a first pass, the full output is attached.
I've opened several issues:
#3204763: Fix mismatched sprintf calls
#3204764: PHPUnit assertions do not return a value
#3205024: Missing use statement in Drupal\Core\Database\Driver\mysql\Connection
#3205026: Missing use statement in Drupal\Core\KeyValueStore\DatabaseStorage
#3205029: DestinationCategoryTest refers to a non-existent class
#3205031: Missing use statement in Drupal\form_test\Form\FormTestVerticalTabsForm
#3205037: Drupal\Tests\Component\Annotation\PluginIdTest tests a non-existent constructor
Some of the issues raised by PHPStan also already have existing issues open:
#3106455: Undefined variable used in /core/modules/system/tests/src/Functional/FileTransfer/TestFileTransfer.php
#2895933: EntityReverse will always use the 'standard' join plugin because of an undefined variable $def
#2935654: Use of undefined $languages variable in NodeListBuilder::buildRow()
Comment #42
longwaveSome more individual issues spun off from here
#3210888: Undefined static method Drupal\Core\Database\Connection::serialize()
#3210763: MailManagerTest::testGetInstance() is buggy
This one already has an issue open:
#2595025: None validator incorrectly handles numeric arguments
Comment #44
longwaveMarking "needs review" to try and get some eyes on this. The latest run says 5 errors though I only really see 3:
The second one is https://github.com/mglaman/phpstan-drupal/issues/184, not sure what to do about the other two; I can't reproduce the internal error locally on that file on its own.
Comment #45
daffie CreditAttribution: daffie commentedComment #46
longwavePHPStan has a 1.0 release: https://phpstan.org/blog/phpstan-1-0-released
I'm sure I saw @alexpott or someone similar asking for stable releases if we are to include this into core, so hopefully the release of a 1.0 will help with that.
Comment #48
mondrakePure reroll, rebased on 9.4.x.
@longwave would you mind changing the MR target brach to 9.4.x? This can only be done by the creatore of the MR.
Comment #49
mondrakePer #3190585-5: [META] Run PHPStan on Drupal core, I would suggest to rescope this issue to
Comment #50
mondrakeSomething is wrong with mglaman/phpstan-drupal autoloader I am afraid ...Class PHPStan\Drupal\ServiceMap not found
is right, in release 1 the namespace was changed fromto
Edit - I was wrong here, it’s a setup that needed to be adjusted instead
Comment #51
mondrakeRe. #50, also contrib module testing (that has PhpStan enabled) fails now:
see https://dispatcher.drupalci.org/job/drupal_contrib/506195/artifact/jenki... for instance, the xml results file is 0-size
Comment #52
Gábor Hojtsy@mondrake: can you submit an infrastructure issue for this (assuming this is about the drupalci setting to run phpstan)? Thanks!
Comment #53
mondrake#52 not sure, I'm pretty new here, right now I think it's an issue with mglaman/phpstan-drupal instead, but need to understand better before raising upstream
Comment #54
mondrakeTrying to create a baseline with
../vendor/bin/phpstan analyze --generate-baseline
fails withSo we probably need to address at least some of the errors right at the beginning before we even create a baseline.
Comment #55
Gábor HojtsyRe #51, I submitted #3248706: PHPStan fails for contrib due to outdated neon configuration that should only affect deprecation checking for contrib projects with drupalci, which is a different use case for phpstan, but I proposed a fix there.
Comment #56
mondrakeSo re. #51 I also filed https://github.com/mglaman/phpstan-drupal/issues/222 upstream.
Comment #57
mondrakeI think a review now would be nice.
Comment #58
mglamanI just released https://github.com/mglaman/phpstan-drupal/releases/tag/1.0.1 which fixes autowiring AND includes code for class resolving.
For example:
It understands the class returned from
getInstanceFromDefinition
Comment #59
mondrakeComment #60
mondrakeThanks for reviews @longwave and @alexpott.
Comment #61
alexpottI think adding this to 10.x only when it opens might make this easier. So +1 to that idea.
Comment #62
mondrakeChanged target release per #61.
Comment #63
mglamanThe phpstan.neon.dist is wrong, in my opinion. Why isn't it including the proper extension.neon?
It'd be even simpler if phpstan/extension-installer was used (no need to include extension.neon)
This also doesn't include phpstan deprecation rules to catch usages of deprecated code. Maybe that's a follow up?
Comment #64
mondrakeIMHO it should be done here, given we're adding the tools in this issue.
Dunno, can you help? Feel free to push on the fork, BTW
Comment #65
mondrakeThere’s not a phpstan-drupal-deprecations release 1, though, is that right? Latest release is 0.11.1 on packagist.
Comment #66
mglamanYeah, I can help. I just didn't have time today to push, so I wanted to leave a comment. I'll help poke at this tomorrow!
https://packagist.org/packages/phpstan/phpstan-deprecation-rules#1.0.0 there is a 1.0.0. All support (core) extensions had compatible releases.
Comment #67
mglamanAnother setting to consider: max number of processes. PHPStan supports multiple threads by default and maximizes based on the number of CPUs. It seems like it might be a good idea to set a limit on that.
Documentation: https://phpstan.org/config-reference#parallel-processing
Scheduling logic: https://github.com/phpstan/phpstan-src/blob/a97bdead71d24694dfe2bbe96de8...
CPU count detection logic: https://github.com/phpstan/phpstan-src/blob/6172a47571c790b429d7f341313e...
Comment #68
mglamanThis one will be hard to debug:
It does not occur for me locally with a clone of the issue fork and
composer install
:Comment #69
mondrakeOut of the latest run https://dispatcher.drupalci.org/job/drupal_patches/103478/console, I think we're now narrowed to a list of errors that must be solved prior to being able to run PHPStan even on level-0.
In particular, we have:
1. some errors that are internal to PHPStan processing. These errors prevent even creating a baseline. ATM there are three of them:
2. Some errors that can not be added to the baseline file, and therefore prevent a clean (=error code 0) run of PHPStan, like for instance:
Comment #70
mondrakeAlso, we need to fix #3248859: AccessAwareRouter fails PHPStan-0 before.
Comment #71
mglamanReplicated error for
It's due to phpstan-drupal code in handling loadIncludes. Opened an issue: https://github.com/mglaman/phpstan-drupal/issues/232
Comment #72
mglamanI just released phpstan-drupal:1.0.3 and pushed the update here, which fixes the two
assert($type instanceof ObjectType)
errors.Comment #74
mallezieI've created a new branch to check this against D10. Also phpstan and phpstan-drupal are updated, so some things have changed.
The good news is i've managed to get a baseline out of phpstan. With some fixes. In this i found 403 errors.
Running locally i get following errors, which should be fixed first so a baseline could be generated.
#3248859: AccessAwareRouter fails PHPStan-0
#3254962: Return type in ErrorContainer
I included some workarounds for those (which are probably wrong) to have PHPStan working. Issues are created for those.
#3254965: Remove deprecated Statement class Duplicate of below
#3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
The above has issues with the database statement class, which is going to be removed anyhow. So i copied over the previous adjustments but this class is scheduled for removal.
Then there is one issue pointing to LinkItemTest
#3254966: PHPStan error LinkItemTest
This is one i don't fully understand, commented out an assert to have it pass, but this is probably not the best appraoch off course.
This issue should then possible be postponed on the above ones, and then the baseline should be inspected to see what we best would fix before committing.
Comment #76
mallezieStill playing around with the MR. What i think still needs to change is the usage in drupalci and the commit-code script.
PHPStan recommends to run it on the entire codebase (with a baseline) and never on seperate files. Therefore the usage in the commit-code script looks incorrect to me.
I think we should run it on the entire codebase on the end of the commit code script (which runs also in drupalci).
Also noticing here that i think the baseline is not taken into account, otherwise phstan should return with no errors.
Comment #77
mondrakeToo many MR branches, now it's hard to follow. Going back to good old patches.
Comment #78
mondrakeComment #79
mondrakeComment #81
SpokjePatch #79 after running
COMPOSER_ROOT_VERSION=10.0.x-dev composer update --lock
Comment #82
SpokjeComment #83
mondrakeWe should update phpstan/phpstan to 1.2.0 and mglaman/phpstan-drupal to 1.1.3
Comment #84
SpokjeAttached patch should do just that, and bring composer
plugin-api-version
back to the original 2.1.0Comment #85
mondrakeTry fixing the ErrorContainer issue, that produces errors on PHPStan run
Comment #86
mondrakeIgnore extending @internal classes.
Comment #87
mondrakeComment #88
mglamanCan you summarize where this happened? When we added this rule, I didn't think it would effect core. And it shouldn't trigger in shared namespaces (core modules extending core internals shouldn't error either, I suppose)
Comment #89
mondrake#88 sure, see the testrun results of #85, https://dispatcher.drupalci.org/job/drupal_patches/107486/consoleFull
Comment #90
mondrakeIgnore not found classes, and fixes for Statement / StatementEmpty (due to be removed from D19 though).
Comment #91
mondrakeComment #92
mondrakeNot found classes cannot be ignored - this becomes a stopper. Added more
#[\ReturnTypeWillChange]
annotations.Comment #93
mondrakeComment #94
daffie CreditAttribution: daffie commentedPatch looks good.
These lines have tabs.
Do we really need the part: "sudo -u www-data"?
This change is out of scope for this issue.
So this part does not need to be committed?
Why are we removing the StatementInterface?
I think that these changes will cause a BC break. Do we really need them? Can we ask @Beakerboy what it will do to do SQL Server database driver?
Can you explain to me why we have this exception here? The class is overriding the method __construct().
Can we create a followup issue to fix this problem in PHPStan?
Could we create a followup issue to fix this problem in PHPStan?
This need to be fixed in core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php.
This should to be fixed. Can we add the static variable migrateDumpAlter?
Can we fix this one. It does not sound very difficult to fix.
Can we create a followup issue to fix this?
Can we fix this or create a followup issue for it.
Can we fix this or create a followup to fix it. This should not be that difficult to fix.
Can we fix this. Should not be that difficult.
Can we fix this. Should be not that difficult.
Can we fix this. Should not be that difficult.
Can we fix this. Should not be that difficult.
Can we fix this or create a followup to fix this.
Why is this file causing a problem for the baseline generation? What do we need to do to fix it? THere are also tabs on the comment lines.
Which of the following common error need a followup so that they can be removed?
Comment #95
mondrakeThanks for review @daffie, sorry I forgot to change status to NW, this patch is still far from being committable.
The idea is
In order to do so, we need to have a zero-error run of PHPStan. Unfortunately (see last test run log https://dispatcher.drupalci.org/job/drupal_patches/107500/consoleFull), this is not the case:
that cannot be ignored nor added to the baseline, so we need to solve upfront
should be better fixed before commit, it's currently being looked at https://github.com/mglaman/phpstan-drupal/pull/279, once solved we will need updating to a new version of both phpstan/phpstan and mglaman/phpstan-drupal
Comment #96
mondrakeForgot to mention... nothing prevents to start tackling any of the baseline or the ignored issues right now. We do not have to wait for this issue to land. If anybody opens an issue, please tagit 'PHPStan-0' so we can have an overview of what's going on.
Comment #97
mglamanI think there's a bug in the PHPStan Drupal rule, an issue would need to be investigated in https://github.com/mglaman/phpstan-drupal/issues
These all refer to Drupal issues, right?
See https://github.com/mglaman/phpstan-drupal/issues/228, https://www.drupal.org/project/drupal/issues/3254966, https://github.com/phpstan/phpstan/issues/6231
---
This issue should generate the baseline and fixes made afterwards, in my opinion. Unless the crash is critical.
Comment #98
mondrakeComment #99
mondrakeComment #100
kim.pepperUpdated composer.lock with
COMPOSER_ROOT_VERSION=10.0.x-dev composer update --lock
Comment #101
daffie CreditAttribution: daffie commentedMost of my points from comment #94 still stand.
Comment #102
alexpottIf doing one file at a time takes a long time because of bootstrapping etc... then we should do what we do for cspell and pass all the files in in one go. Plus we should also configure this to do a full scan when the phpstan config files have changed.
Comment #103
mondrakeComment #104
mondrakeComment #105
mondrakeComment #106
alexpottThis is looking great.
So now we need to implement a full scan if
core/phpstan.neon.dist
orcore/phpstan-baseline.neon
changes.I don't think this needs to be here.
Comment #107
mondrakeYes, the problem here is that a full scan will not currently pass (see IS point 1), and I have no idea how to fix that - locally it seems OK.
Comment #108
mondrakeComment #109
mondrakeComment #110
mondrakeDone #106, now we fail on full scan as per #107. I found in #108 one reason for two remaining issues, for the rest I'm out of ideas ATM.
Comment #111
alexpott@mondrake if I run
locally after applying this patch I get no errors.
Maybe the issue summary needs an update - I think you've solved quite a few of the problems listed.
Comment #112
mondrake#111 same here... so it is a DrupalCI problem. Concurrency?
Comment #113
mondrakeTrying to restrict max number of concurrent processes, see #67
Comment #114
mondrakeBetter. Trying to disable concurrency altogether.
Comment #115
mondrakeGosh... different levels of parallelism give different results...
Comment #116
mondrakeRevert phpcs.xml.dist changes
Comment #117
mondrakeComment #118
Taran2LLet's try to debug
Comment #119
mglamanI'm copying something I shared in Slack with @alexpott.
We should try setting the cache folder to a relative directory:
Otherwise the temp folder is generated with
sys_get_temp_dir()
. My concern was this conflicting with other workspaces in Jekins. But @alexpott suggestedWe should try setting the tmpDir param and see if it makes things more reliable.
Comment #120
mondrakeWe need to create a temp directory before running PHPStan then? Named like what and where?
Comment #121
alexpottLet's borrow some things from https://git.drupalcode.org/project/infrastructure/-/commit/4379df685f205...
Comment #122
Taran2Lhi @alexpott, from my run #118 with debug on the problematic php file wasn't the problem, but it ran out of memory.
--debug
mode does two things:So, I guess one of the above causes the issue (or their combination + DrupalCI setup)
BTW, running it locally with PHP8.0 cannot fit within 3G, it consumes in the end ~7.0G
Comment #123
Taran2LComment #124
Taran2LComment #125
alexpott@Taran2L yep for a single process you need 7G of memory :)
#121 changes the tmp dir used by setting PHP vars - I tested this locally and it works. We definitely should not be setting a temp dir in the phpstan config file - that'll mess up using the script locally. Anyhow #121 seems to prove that the problem is not due to the temp dir because it does not change the results.
@Taran2L please post interdiff so people can see what you are changing / trying out - not doing that makes people have to work harder.
Comment #126
alexpottHere's the missing interdiff... and yeah as pointed out in #125 the temp directory is not the problem. #121 used a custom temp dir for drupalci and it makes no difference.
Comment #127
Taran2L@alexpott,
- memory consumption: this is quite weird, running multiple processes consumes only ~600M on 8.0 and ~200 on 8.1, but single thread is killing it with ~7G - probably needs to addressed by phpstan
- interdiff - sorry, will do in the future
So, cache directory seems like not an issue, as it fails with an empty cache as well. See #123 and #124
Well, let's maybe try a different PHP version ...
Comment #128
alexpottHere's another thought... it's apcu and we're running into evictions that are affecting the composer classmap that's stored there. Let's disable it. To me this explains the different behaviour with different numbers of processes and different PHP versions.
Fingers-crossed.
Comment #129
alexpott#697946: Properly deprecate module_load_include() and move it into \Drupal::moduleHandler() service introduced two new issues to add to baseline...
Comment #130
Taran2L@alexpott, great find! seems like it's green already, but patch actually comments out a few things, so those have to be brought back
The other thing is that phpstan is fixed to 1.2.0, while 1.3.1 is available; the same with mgalaman/phpstan-drupal
I think we should update before committing. Thoughts?
Comment #131
alexpottSure - this updates all the dependencies added here and updates the baseline to reflect the changes in phpstan-drupal.
Comment #132
alexpottWe shouldn't be deciding how many processes to run... let's let phpstan do that.
Comment #133
alexpottWith #131 a run on all the files:
With #132
So that's v nice.
Comment #134
mondrakeSo APCu caching eh? Great find @alexpott, kudos++
Now the patch is 5 times bigger than before, due to increased baseline - is it possible to move some of it to patterns in the ignoreErrors section of phpstan.neon.dist instead?
Comment #135
alexpott@mondrake good point about the ignoreErrors... the private call thing in tests is bogus anyway.
Comment #136
mondrakeIMHO we should commit with composer.json constraints in line with the version we are actually starting using
Comment #137
alexpottSure why not. tbh the whole dev dependency pinning and locks is all interesting.
Comment #138
alexpottThese reports are not correct. Opened https://github.com/mglaman/phpstan-drupal/pull/292 to deal with this.
Comment #139
malleziereportUnmatchedIgnoredErrors: false
Should that be in the phpstan config?
Having this removed always forces a clean baseline, which we should strive for?
Comment #140
mglamanI believe that reportUnmatchedIgnoredErrors was turned off when trying to do scans of only modified files for pre-commit. If pre-commit now does a full scan, we can remove that.
Comment #141
mglamanAlso:
phpstan-drupal 1.1.6 fixes #138
phpstan 1.3.2 fixes the problem where renamed trait methods were considered private https://github.com/phpstan/phpstan/issues/6306
so we need some bumps
Comment #142
alexpottUpdating things again.
Comment #143
mglamanThis is going to cause problems. This is why we had to add
reportUnmatchedIgnoredErrors: false
Everything not hit in the baseline will report as an error if only scanning those files. It's best to just scan all files on precommit. Unless someone can do a fake commit locally and verify.
Comment #144
alexpott@mglaman I think we can get the best of both worlds.
Comment #145
alexpottNow with commentary to explain what's going on.
Comment #146
cmlaraExpanding on #143:
What about when editing a file that is extended by other files that are not included in the commit?
It would appear to me that there is a possibility by not scanning the full code base that a list of new PHPStan errors could be committed but not appear until either a baseline is updated or another committer goes to edit a specific file.
For example a couple scenarios I can think of:
Removing a declared property that is not utilized in a Base class however is utilized in an (unedited) extending class? (attempt to access an undefined property error)
Possibly changing the type signatures on method parameters or on its returns in docblocs having a ripple effect? (Parameter type mismatch errors)
Comment #147
Taran2LComment #148
mglaman@Taran2L it helps to summarize the changes. It looks like you went ahead and tried to remove some reported errors. I think the main goal here is not to fix things but only the minimum required to make PHPStan run, then doing the fixes once this merges.
RE #146 I agree. Pre-commit hooks are for the maintainers when officially committing an issue's patch/MR. Correct? If so, it should run on all the things.
Comment #149
mondrakeMade some updates to the IS.
Comment #150
mondrakeFiled #3257654: Fix PHPStan L0 failures that cannot be included in baseline as a quick win spin-off of this issue.
Comment #151
mondrake@Taran2L if you want to start addressing PHPStan issues you're welcome, but please file separate issue for those and tag them 'PHPStan-0', like for instance #3257654: Fix PHPStan L0 failures that cannot be included in baseline.
Comment #152
Taran2L@mglaman, well it (kinda) make sense, but a) there were a few code changes before my updates b) I've addressed only simpl(e|ish) things :)
Checking @mondrake comments: are those unignorable issues only?
In general, I'm OK with splitting patches, but please then confirm that this is the way we are going.
1. Composer dependencies
For PHPStan currently we require: drupal extension + extension loader + phpstan (tool)
But for PHPCS we require: drupal extension only
Should it be like that? Should we align approach with PHPCS as well (and maybe some other tools)?
2. How we proceed with PHPStan config further in context of ignoring the errors
Seems like there are a lot of ways how to ignore errors: put them into the config file directly, use baseline and/or use
phpstan-
prefixed PHPDoc tags.For example, one the of reported issue is:
This error is not valid as this code is actually testing for proper service deprecation. So, how to tell PHPStan to ignore it? I believe it requires a follow-up?
3. Files excluded for processing
Seems like all neon config files are being merged together in a weird way, as
excludePaths
is Drupal config does not override the one from the phpstan-drupal plugin, but just extends it, and it's not possible to relax that limitation (thus fails for the #147)Any ideas, @mglaman?
Actually, there are only 2 files in fixtures that phpstan cannot swallow (and there are other files required by tests causing issues)
PHPStan also support a newer way of excluding files:
So, this issue raises 2 questions here:
4. Baseline file uses tabs
Seems like we cannot do anything with that, right?
5. Rule
RenderCallbackRule
generates too much false positivesLet's maybe disable it for now?
Comment #153
Taran2LOK, new patch addressing issue with LinkItemTest only
Comment #154
mglamanphpstan-drupal does not have a strict requirement. PHPStan moves fast. It makes sense to pin to a specific PHPStan here.
Core hasn't had it's deprecations fixed in 10.x as far as I know. Or that means something was missed. Baseline should only be autogenerated.
I don't think phpstan-drupal has these excludes in it's config. That's drupal-check
You can't.
This already has its own issue and a PHPStan issue. Please look at it. It's tagged appropriately in the core issue queue, if not linked here already. We shouldn't be changing test code which passes due to crash in PHPStan
Comment #155
Taran2LOK, makes sense
That's understandable, what I was trying to explain is: there should be a document/approach on how to work with Drupal code in conjunction with PHPStan checks. For example: some service is being deprecated => test is added that verifies deprecation => PHPStan will complain on that specific line. So, baseline? Ignore errors within the config file?
phpstan-
PHPDoc tags?I think it is https://github.com/mglaman/phpstan-drupal/blob/main/extension.neon#L6
Oh :( I guess this is a PHPStan limitation. Major one tbh (not blocking us from using it of course)
But this patch before my changes has a lot of code changes in order to PHPStan to work. Then, imho code can and should be changed, isn't it a reason we do all this ? And that particular test is not checking field API, but how link item process NULL values, so it does not matter whether it
$entity->field_aaa
or$entity->field_aaa[0]
Comment #156
mondrake@Taran2L
Please read the issue summary, it says
After #3257654: Fix PHPStan L0 failures that cannot be included in baseline is committed, there will be no code changes in THIS patch. All your work has merit, every change will require its own discussion in a separate issue than this one, so that in this issue we can focus the discussion in getting PHPStan in without debating on the fixes that PHPStan will sparkle.
Comment #157
alexpottBack to #145 and rerolling on top of 10.0.x so now this includes no code change. Bumped phpstan version to the latest too.
Re #146 I think that the savings of only scanning changed files for the majority of changes are probably worth it given the amount files Drupal has and testing drupal.org does. We can revisit this choice once we have data to support how often the full scan breaks.
Comment #158
alexpottAdded dependency evaluations for phpstan/phpstan, phpstan/extension-installer and mglaman/phpstan-drupal
I'm going to file an issue against mglaman/phpstan-drupal to discuss whether we can remove the nette/* dependencies to slim things down a bit.
We still need a CR here to tell core devs how to use it.
Comment #159
alexpottOpened https://github.com/mglaman/phpstan-drupal/pull/297 to put mglaman/phpstan-drupal on a dependency diet :)
Comment #160
alexpottAdded dependency evaluation for webflo's drupal-finder
Comment #161
mondrakeWith deps evaluation I think there's not much else to do but CR and release notes, but I suppose we can bring to release managers' eyes already.
Comment #162
alexpott@mondrake a release manager's eyes are already here. I discussed this issue with @catch already today hence the work I've put into dependency evaluations. Setting back to needs review because we need to:
Tagging with release highlights because I think the addition of the tool is quite big news for core developers at least and might inspire Drupal projects to adopt it (if they haven't already). And this all helps with code quality and to help contrib update in time for the next core release.
Comment #163
alexpottThe upstream fix to not use nette/finder has landed and been released - thanks @mglaman.
So now the dependency evaluations are complete.
Comment #164
mondrakeWow that was fast!
Comment #165
daffie CreditAttribution: daffie commentedShould we not add phpstan-partial.neon to this list? In file there is the text that the file should not be changed, only somebody can miss that in the future.
Edit: I have run the script
./core/scripts/dev/commit-code-check.sh
on my local machine and the result was good. When I removed the following code from the patch to test the changed file part, the result was also good:Comment #166
longwave> Should we not add phpstan-partial.neon to this list?
I think not - if we change phpstan-partial.neon we want a partial run, as the file is only used on a partial run.
Comment #167
daffie CreditAttribution: daffie commentedAll the code changes look good to me.
I have tested the patch on my local machine.
The patch is for me RTBC.
We now only need a change record and a release managers review.
Great work everybody!
Comment #168
daffie CreditAttribution: daffie commentedAdded the missing CR.
The patch was for me already RTBC.
Changing the status to RTBC for the release manager review.
Comment #169
catchThe dependency evaluation looks good. While we haven't committed to adding rector rules to core yet, this would be a prerequisite to doing so. Removing the needs release manager review tag.
Comment #170
xjmThanks also for the very good dependency evaluations!
We should add these deps to https://www.drupal.org/about/core/policies/core-dependency-policies/core... before commit (we can always revert the docs update if something goes awry before we commit this).
Comment #171
xjmMeant to tag.
Comment #172
neclimdulIts weird to me this isn't fixing the phpstan build step in CI. Hacking this into code check feels... problematic. It also means we're blocking out contrib from follow core's lead on this.
https://git.drupalcode.org/project/drupalci_testbot/-/blob/dev/src/Drupa...
Comment #173
alexpott@neclimdul I think we should drop the idea of plugins for thing like phpstan, phpcs etc in DrupalCI and make it simpler to run scripts (like core is now doing)... and every other CI. This will happen when DrupalCI becomes GitlabCI.
Comment #174
alexpottFWIW there's nothing to stop contrib from having their own drupalci.yml and running phpstan via a container command and it'll be easier when phpstan is part of core-dev.
Comment #175
neclimdulDidn't say this in the last comment but I want to say YAY! I'm super excited about this because phpstan (and psalm) have been super helpful for catching potential bugs and edge cases in code outside of Drupal. And I'm looking forward to what it might find in Drupal.
Looking at the patch a bit closer I have some concerns though.
I guess, mostly I just have concerns with this running partial checks.
As an example of how this might be a problem, consider the case where I modify an interface. Just checking the interface file itself would probably pass but it wouldn't catch if that interface change breaks an implementing classes or any code using that interface. For sure this would probably get caught by testing since we've got pretty solid coverage but it means there's a whole class of bugs phpstan can't check for. Since basically ever code change is going to affect code outside the file this concept extends to basically every patch.
NR for discussion as maybe there's a counter argument but I really think we should only be running full checks either in code-check or probably better in drupalci step.
Comment #176
neclimdul@neclimdul I think we should drop the idea of plugins for thing like phpstan, phpcs etc in DrupalCI and make it simpler to run scripts (like core is now doing)... and every other CI. This will happen when DrupalCI becomes GitlabCI.
That's not my understanding of how we're working through the gitlab conversion. In every gitlab pipeline I've implemented these would be separate pipeline
stepsjobs similar to how drupalci treats plugins. This provides explicit report handling and parallelization. So actually preserving those plugins provides a more direct conversion process.Comment #177
mglamanI am going to echo that the following scares me:
There is no point in running PHPStan if we don't analyze the entire codebase based on the changes. What this does do is trust that a contributor ran PHPStan locally to see if the baseline was modified. Otherwise, it can run without any consequence. And we may not even know if the baseline was fixed/cleaned up at all.
Also, that portion needs to be documented – how to regenerate the baseline (if it is, I missed that, apologies.)
Comment #178
alexpottRe #175 / #177 - this has already been debated. Drupal has a massive codebase and running this on every test on every issue comes at a cost both time and money. The idea is to try out partial tests and see how often it breaks - if it is once a month then it's manageable - if it is all the time then it is not.
Given this has been discussed already - see #146 and #157's response. The tldr; we can revisit the partial decision once we actually have some data. But upfront we know the extra work will have a cost so let's not take it on. Given this has all been discussed already setting back to rtbc.
Comment #179
alexpottI've added the CLI commands to regenerate the baseline to the CR - https://www.drupal.org/node/3258232
Comment #180
neclimdulI'm sorry I've dredged up a previous discussion. I understand the frustration that causes late in an issue. I re-iterate my opinion that I think the decision reached is very wrong adding cost with not benefit and destined to cause maintenance headaches and leave it at that rather then status toggling.
Comment #181
alexpott@neclimdul but the decision is not final - it's wanting the additional cost to be justified. We'll know that soon enough - this is not an API decision. If we regret the choice it is a very simple change to change it.
Comment #182
alexpottUpdated phpstan-drupal to get the benefits of @mglaman's work on the render callback rule.
Comment #183
mglamanTrue, that makes sense. Let's just see where it goes. We're better off than we were before.
+1 on adding to the CR
Comment #184
mglamanFYI I made an issue for these errors in PlaceholderGenerator and Renderer. It's due to the array_key_intersect call https://github.com/mglaman/phpstan-drupal/issues/303
Glad to see 1.1.8 resolved the erroneous callback errors I generated in 1.1.5
Comment #185
mondrakeWorking on this
Comment #186
mondrakeAfter upgrading to Symfony 5.4 we now have a problem upstream:
Comment #187
mondrakeComment #188
mglamanCan you open an issue on phpstan-drupal to bump the dependency upper constraint
Comment #189
mondrake@alexpott opened https://github.com/mglaman/phpstan-drupal/pull/306 already
Comment #190
mglamanRelease tagged https://github.com/mglaman/phpstan-drupal/releases/tag/1.1.9
Comment #191
mondrakeRerolling.
Comment #192
alexpottRe-rolled with the new version.
In order to make it green we need to throw some exceptions in unsupported methods I think that this is okay. As getting this in will mean that we'll have to confront these issues in the issue that causes them rather than on this issue.
The isObjectInitialized() does not conform to the interface to this is not an ignorable error for PHPStan - we could add this path to the phstan ignored path but the fix of throwing an exception is the correct one so let's do that here and get this one done.
Comment #193
mondrake+1... this issue has already captured a number of these, time to get this in. Running partial vs full scan is still an open discussion, but regardless of that for sure with this in we will improve future code quality.
Comment #194
mondrakeComment #195
catchStill needs the docs update per #17 but otherwise looks good.
Not sure exactly how we'll run down all the exclusions we're adding - presumably we don't get notified when they're no longer needed, so it'll have to be an occasional manual clear-out?
Comment #196
mondrake#195
Basically two (well, three) ways:
a) exclusions that are part of the
ignoreErrors
section of the configuration file: here we will need individual issues to remove individual entries (if possible), and fix all the failing things connected with that removal in the same issue.b) exclusions that are part of the baseline file: errors may be removed by specific issues or as part of other issues. When an error does not occur in a file anymore (because that is fixed, let's say, inadvertently :)), then the
reportUnmatchedIgnoredErrors
setting in phpstan will trigger for files changed and report that. DrupalCI will then fail - so the patch/MR author will have to also cleanup the baseline from the no longer occurring errors. Also, it'll be possible to remove from baseline in dedicated issues - in a way similar to that of removing from ignoreErrors.Comment #197
alexpottI've addressed the request for documentation updates in #171 - see https://www.drupal.org/about/core/policies/core-dependency-policies/core...
Comment #198
mallezieGreat to see this moving forward this fast! Cannot wait to start fixing things.
Wen't through the patch again, and cannot spot any remarks (which were not already adressed). Good to see we actually only ignore one file for now. (LinkItemTest) This gives a clean baseline to start working.
So +1 RTBC from me here.
Comment #200
catchI think ctrl-F failed me on the docs page...
It took about ten minutes for phpstan to run on my local git pre-commit hooks, freezing up my entire machine, so personally glad we're trying one file at a time to start with.
Sounds like mostly manual removal of exclusions in dedicated issues but that's how we've done lots of other things, so let's unblock all that.
Comment #201
Taran2L@catch, that's weird .. it takes ~3-4m on my Late 2016 MacBook Pro, maybe on pre-commit it runs in 1 thread, weird
Comment #202
mondrakeI think locally people should do https://phpstan.org/user-guide/result-cache... which should speed up complete runs. That's not possible in Drupal I learnt, since you cannot store away the cache across buils.
Comment #203
neclimdulfwiw, took about 2 min for me or approximately one functional tests with 10-12 tests.