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.
CommentFileSizeAuthor
#192 3178534-191.patch75.37 KBalexpott
#192 pseudo-interdiff.txt2.72 KBalexpott
#182 3178534-182.patch74.73 KBalexpott
#182 163-182-interdiff.txt20.18 KBalexpott
#163 3178534-163.patch84.04 KBalexpott
#163 157-163-interdiff.txt9.92 KBalexpott
#157 3178534-157.patch89.81 KBalexpott
#157 145-157-interdiff.txt4.18 KBalexpott
#153 3178534-153.patch97.45 KBTaran2L
#153 interdiff-145-153.txt1.71 KBTaran2L
#147 3178534-147.patch108.87 KBTaran2L
#147 interdiff-145-147.txt25.92 KBTaran2L
#145 3178534-145.patch96.37 KBalexpott
#145 144-145-interdiff.txt449 bytesalexpott
#144 3178534-144.patch96.2 KBalexpott
#144 142-144-interdiff.txt1.21 KBalexpott
#142 3178534-142.patch95.79 KBalexpott
#142 137-142-interdiff.txt30.41 KBalexpott
#137 3178534-137.patch113.42 KBalexpott
#137 135-137-interdiff.txt2.38 KBalexpott
#135 3178534-135.patch113.32 KBalexpott
#135 132-135-interdiff.txt373.08 KBalexpott
#132 3178534-132.patch402.85 KBalexpott
#132 131-132-interdiff.txt285 bytesalexpott
#131 3178534-131.patch402.9 KBalexpott
#131 129-131-interdiff.txt406.16 KBalexpott
#129 3178534-129.patch84.66 KBalexpott
#129 128-129-interdiff.txt2.43 KBalexpott
#128 3178534-128.patch85.05 KBalexpott
#128 121-128-interdiff.txt1.49 KBalexpott
#124 3178534-124.patch85 KBTaran2L
#123 interdiff-118-123.txt1.17 KBTaran2L
#123 3178534-123.patch84.97 KBTaran2L
#121 3178534-121.patch85.28 KBalexpott
#121 117-121-interdiff.txt1.46 KBalexpott
#118 3178534-118.patch85.04 KBTaran2L
#117 3178534-117.patch85.02 KBmondrake
#117 interdiff_116-117.txt1.69 KBmondrake
#116 interdiff_114-116.txt912 bytesmondrake
#116 3178534-116.patch84.92 KBmondrake
#114 interdiff_113-114.txt297 bytesmondrake
#114 3178534-114.patch85.52 KBmondrake
#113 interdiff_109-113.txt285 bytesmondrake
#113 3178534-113.patch85.52 KBmondrake
#109 3178534-109.patch85.47 KBmondrake
#109 interdiff_108-109.txt2.35 KBmondrake
#108 3178534-108.patch85.02 KBmondrake
#108 interdiff_105-108.txt583 bytesmondrake
#105 3178534-105.patch84.85 KBmondrake
#105 interdiff_104-105.txt1.96 KBmondrake
#104 3178534-104.patch84 KBmondrake
#104 interdiff_103-104.txt2.71 KBmondrake
#103 3178534-103.patch89.45 KBmondrake
#103 interdiff_100-103.txt2.55 KBmondrake
#100 3178534-100-interdiff.txt802 byteskim.pepper
#100 3178534-100.patch89.52 KBkim.pepper
#98 interdiff_93-98.txt13.17 KBmondrake
#98 3178534-98.patch89.83 KBmondrake
#93 3178534-93.patch96.84 KBmondrake
#93 interdiff_91-93.txt3.51 KBmondrake
#92 interdiff_91-92.txt3.51 KBmondrake
#92 3178534-92.patch96.84 KBmondrake
#91 interdiff_87-91.txt2.68 KBmondrake
#91 3178534-91.patch93.76 KBmondrake
#90 interdiff_87-88.txt2.68 KBmondrake
#90 3178534-88.patch93.76 KBmondrake
#87 interdiff_85-87.txt423 bytesmondrake
#87 3178534-87.patch91.99 KBmondrake
#86 3178534-86.patch91.99 KBmondrake
#86 interdiff_85-86.txt424 bytesmondrake
#85 3178534-85.patch91.95 KBmondrake
#85 interdiff_84-85.txt1.17 KBmondrake
#84 3178534-81.patch91.32 KBSpokje
#84 interdiff-80_81.txt6.53 KBSpokje
#81 3178534-80.patch91.48 KBSpokje
#81 interdiff-79_80.txt2.04 KBSpokje
#79 3178534-79.patch90.86 KBmondrake
#79 interdiff_77-79.txt577 bytesmondrake
#78 interdiff_77-78.patch430 bytesmondrake
#78 3178534-78.patch90.54 KBmondrake
#77 3178534-77.patch90.49 KBmondrake
#41 phpstan2.txt45.4 KBlongwave
#2 phpstan-type-fixes-3178534-2.patch4.11 KBklausi

Issue fork drupal-3178534

Command icon 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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

klausi created an issue. See original summary.

klausi’s picture

Here is the batch of current problems I run into.

alexpott’s picture

+++ b/core/lib/Drupal/Core/Form/FormStateInterface.php
@@ -491,7 +491,7 @@ public static function hasAnyErrors();
-   * @param string $message
+   * @param string|\Drupal\Component\Render\MarkupInterface $message

These 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.

klausi’s picture

Maybe 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:

# PHPStan is not run on Drupal CI yet, so this file is just a helper for
# manually running PHPStan.
parameters:
  level: 1
  fileExtensions:
    - inc
    - install
    - module
    - php
  paths:
    # Just this part is enabled for checking for now, expand later.
    - lib/Drupal/Component
  ignoreErrors:
    # new static() is a best practice in Drupal, so we cannot fix that.
    - "#^Unsafe usage of new static\\(\\)\\.$#"
    # Local variables created from including a PHP file, we cannot fix that.
    -
      message: "#^Undefined variable\\: \\$overrides$#"
      count: 1
      path: lib/Drupal/Component/Transliteration/PhpTransliteration.php
    -
      message: "#^Variable \\$overrides in isset\\(\\) is never defined\\.$#"
      count: 1
      path: lib/Drupal/Component/Transliteration/PhpTransliteration.php
    -
      message: "#^Undefined variable\\: \\$base$#"
      count: 1
      path: lib/Drupal/Component/Transliteration/PhpTransliteration.php
    -
      message: "#^Variable \\$base in isset\\(\\) is never defined\\.$#"
      count: 1
      path: lib/Drupal/Component/Transliteration/PhpTransliteration.php

I fixed 2 minor issues, but then I think PHPStan found the first real bug in ProxyBuilder:

 ------ ------------------------------------------------------- 
  Line   ProxyBuilder/ProxyBuilder.php                          
 ------ ------------------------------------------------------- 
  169    Variable $proxy_class_shortname might not be defined.  
 ------ ------------------------------------------------------- 

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

alexpott’s picture

One 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

klausi’s picture

klausi’s picture

@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.

klausi’s picture

lib/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.

klausi’s picture

Oh 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.

alexpott’s picture

The 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

klausi’s picture

We 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.

andypost’s picture

@klausi thanks for link, it looks less terrible then 2 years ago

klausi’s picture

Turns 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.

klausi’s picture

Title: Fix various doc comment type hints reported by PHPStan » Start running PHPStan on Drupal core (level 0)
Issue summary: View changes

Updated the issue summary with the plan to enable PHPStan testing.

Will modify the merge request to start with the even lower level 0 next.

daffie’s picture

The testbot is returning with:

19:46:44 [Deprecation] [-ERROR-] No files found for pattern 'jenkins-drupal_patches-72429/artifacts/phpstan/*.xml'. Configuration error?
19:46:44 [Deprecation] Searching for all files in '/var/lib/drupalci/workspace' that match the pattern 'jenkins-drupal_patches-72429/artifacts/phpstan/*.xml'
19:46:44 [Deprecation] Skipping post processing
19:46:44 [Deprecation] No filter has been set, publishing all 0 issues
19:46:44 [Deprecation] Using reference build 'drupal_patches #72426' to compute new, fixed, and outstanding issues
19:46:44 [Deprecation] Issues delta (vs. reference build): outstanding: 0, new: 0, fixed: 0
19:46:44 [Deprecation] No quality gates have been set - skipping
19:46:44 [Deprecation] Health report is disabled - skipping
19:46:44 [Deprecation] Created analysis result for 0 issues (found 0 new issues, fixed 0 issues)
19:46:44 [Deprecation] Attaching ResultAction with ID 'phpstan' to run 'drupal_patches #72429'.

See: https://dispatcher.drupalci.org/job/drupal_patches/72429/console

daffie’s picture

Status: Needs review » Needs work

When I run the command on my local machine I get the following error:

vagrant@drupal92devp:/var/www/drupalvm/drupal$ ./phpstan.sh
Lets run some stans!
Note: Using configuration file /var/www/drupalvm/drupal/core/phpstan.neon.
 594/594 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ -------------------------------------------------------------------- 
  Line   Component/DependencyInjection/Dumper/OptimizedPhpArrayDumper.php    
 ------ -------------------------------------------------------------------- 
  430    Class Symfony\Component\ExpressionLanguage\Expression not found.    
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
 ------ -------------------------------------------------------------------- 

                                                                                                                 
 [ERROR] Found 1 error                                                                                           
daffie’s picture

@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:

 594/594 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ ----------------------------------------------------------------------------- 
  Line   Component/Bridge/ZfExtensionManagerSfContainer.php                           
 ------ ----------------------------------------------------------------------------- 
  132    Cannot instantiate interface Laminas\Feed\Reader\ExtensionManagerInterface.  
  132    Cannot instantiate interface Laminas\Feed\Writer\ExtensionManagerInterface.  
 ------ ----------------------------------------------------------------------------- 

 ------ -------------------------------------------------------------------- 
  Line   Component/DependencyInjection/Dumper/OptimizedPhpArrayDumper.php    
 ------ -------------------------------------------------------------------- 
  430    Class Symfony\Component\ExpressionLanguage\Expression not found.    
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
 ------ -------------------------------------------------------------------- 

 ------ ------------------------------------------------------------------------------------------------------ 
  Line   Core/Cache/Context/CacheContextsManager.php                                                           
 ------ ------------------------------------------------------------------------------------------------------ 
  265    Access to an undefined property Drupal\Core\Cache\Context\CacheContextsManager::$validContextTokens.  
 ------ ------------------------------------------------------------------------------------------------------ 

 ------ ------------------------------------------------------------------------- 
  Line   Core/Cache/PhpBackend.php                                                
 ------ ------------------------------------------------------------------------- 
  255    Access to an undefined property Drupal\Core\Cache\PhpBackend::$storage.  
 ------ ------------------------------------------------------------------------- 

                                                                                                                 
 [ERROR] Found 5 errors                                                                                          
                                                                                                                 
klausi’s picture

Status: Needs work » Needs review

@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.

daffie’s picture

Status: Needs review » Needs work

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.

I 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 :-(

klausi’s picture

Component: documentation » base system
klausi’s picture

Status: Needs work » Needs review

Reverted 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.

daffie’s picture

Status: Needs review » Needs work
klausi’s picture

Status: Needs work » Needs review

Thanks for the review daffie, this is ready to be checked again!

daffie’s picture

Status: Needs review » Reviewed & tested by the community

@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.

daffie’s picture

Title: Start running PHPStan on Drupal core (level 0) » Start running PHPStan on Drupal core (level 0 - part 1)
daffie’s picture

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs release manager review, +Needs change record

Given 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.

andypost’s picture

If 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

andypost’s picture

longwave made their first commit to this issue’s fork.

longwave’s picture

I 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

longwave’s picture

In 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.

longwave’s picture

As 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?

longwave’s picture

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

This seems to be because of core/lib/Drupal/Core/Extension/ThemeInstaller.php:

use Drupal\system\ModuleDependencyMessageTrait;

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

andypost’s picture

Good catch! I bet there's more places to fix, like usage of core in components

longwave’s picture

@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.

longwave’s picture

longwave’s picture

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

longwave’s picture

Title: Start running PHPStan on Drupal core (level 0 - part 1) » Start running PHPStan on Drupal core (level 0)
Status: Needs work » Needs review

Marking "needs review" to try and get some eyes on this. The latest run says 5 errors though I only really see 3:

     Internal error: Internal error: Cannot assign an empty string to a string  
     offset in file                                                             
     /var/www/html/core/modules/link/tests/src/Kernel/LinkItemTest.php          
     Run PHPStan with --debug option and post the stack trace to:               
     https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md       
     Child process error (exit code 255): PHP Warning:  Undefined array key     
     "class" in                                                                 
     /var/www/html/vendor/mglaman/phpstan-drupal/src/Drupal/ServiceMap.php on   
     line 41                                                                    
     PHP Fatal error:  Declaration of                                           
     Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index =     
     null, $constructor_arguments = null) must be compatible with               
     PDOStatement::fetchAll(int $mode = PDO::FETCH_BOTH, mixed ...$args) in     
     /var/www/html/core/lib/Drupal/Core/Database/Statement.php on line 184      

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.

daffie’s picture

Status: Needs review » Needs work
  1. I am missing in core/scripts/dev/commit-code-check.sh a check that when we update the file core/phpstan.neon.dist we run the phpstan check on all files, not just the files that have changed in the patch or MR. See: #3224583: The testbot does not run PHPCS on all files when core/phpcs.xml.dist is changed.
  2. Can we add failures from comment #44 to ignoreErrors list in core/phpstan.neon.dist? I think that the parameter typehint "mixed" is something that will have to wait, because it is PHP 8.0+.
longwave’s picture

PHPStan 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.

mondrake made their first commit to this issue’s fork.

mondrake’s picture

Pure 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.

mondrake’s picture

Per #3190585-5: [META] Run PHPStan on Drupal core, I would suggest to rescope this issue to

Add phpstan config to core (level 0). Enable it on CI, and in pre-commit-script, do not fix any problems, just add a baseline. This way we don't introduce any new phpstan level 0 errors. But can keep this part focussed on adding and running phpstan.

mondrake’s picture

Something 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 from

namespace PHPStan\Drupal;

[...]

class ServiceMap

to

namespace mglaman\PHPStanDrupal\Drupal;

[...]

class ServiceMap

Edit - I was wrong here, it’s a setup that needed to be adjusted instead

mondrake’s picture

Re. #50, also contrib module testing (that has PhpStan enabled) fails now:

Host commands: cd modules/contrib/image_effects && sudo -u www-data /var/www/html/vendor/bin/phpstan analyse --error-format checkstyle -c /var/lib/drupalci/workdir/phpstan/phpstan.neon . > /var/lib/drupalci/workdir/phpstan/phpstan_results.xml
Return code: 1
Output: 
StdErr: PHP Warning:  Undefined array key "class" in /var/www/html/vendor/mglaman/phpstan-drupal/src/Drupal/ServiceMap.php on line 41
Warning: Undefined array key "class" in /var/www/html/vendor/mglaman/phpstan-drupal/src/Drupal/ServiceMap.php on line 41
Configuration parameters excludes_analyse and excludePaths cannot be used at the same time.

see https://dispatcher.drupalci.org/job/drupal_contrib/506195/artifact/jenki... for instance, the xml results file is 0-size

Gábor Hojtsy’s picture

@mondrake: can you submit an infrastructure issue for this (assuming this is about the drupalci setting to run phpstan)? Thanks!

mondrake’s picture

#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

mondrake’s picture

Trying to create a baseline with ../vendor/bin/phpstan analyze --generate-baseline fails with

Error: ] An internal error occurred. Baseline could not be generated. Re-run    
         PHPStan without --generate-baseline to see what's going on.            

So we probably need to address at least some of the errors right at the beginning before we even create a baseline.

Gábor Hojtsy’s picture

Re #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.

mondrake’s picture

mondrake’s picture

Status: Needs work » Needs review

I think a review now would be nice.

  • we need a new release of mglaman/phpstan-drupal including https://github.com/mglaman/phpstan-drupal/pull/223 to solve an issue with autowiring
  • I cannot figure out what is triggering the PHPUnit classes rewrite for BC -- the rewritten classes get in the way of commit-code-checks
mglaman’s picture

I just released https://github.com/mglaman/phpstan-drupal/releases/tag/1.0.1 which fixes autowiring AND includes code for class resolving.

For example:

/**
 * Implements hook_entity_type_alter().
 */
function workspaces_entity_type_alter(array &$entity_types) {
  \Drupal::service('class_resolver')
    ->getInstanceFromDefinition(EntityTypeInfo::class)
    ->entityTypeAlter($entity_types);
}

It understands the class returned from getInstanceFromDefinition

mondrake’s picture

Issue tags: +PHPStan-0
mondrake’s picture

Thanks for reviews @longwave and @alexpott.

  1. mglaman/phpstan-drupal updated to 1.0.1 (thanks @mglaman for quick turnaround!) and the missing 'class' error is gone
  2. still do not understand why the rewritten PHPUnit classes get in the way of commit-code-checks
  3. I do not know how to solve the autoload errors for missing composer/composer, symfony/contracts, psr/log classes (the latter, apparently, intermittent)
  4. several pre-level-0 errors are in deprecated code, that will go away in D10. Is this issue still a D9 thing, or when D10 opens we can target PHPStan on D10 only?
alexpott’s picture

I think adding this to 10.x only when it opens might make this easier. So +1 to that idea.

mondrake’s picture

Version: 9.3.x-dev » 10.0.x-dev

Changed target release per #61.

mglaman’s picture

The phpstan.neon.dist is wrong, in my opinion. Why isn't it including the proper extension.neon?


includes:
	- phpstan-baseline.neon
        - ../vendor/mglaman/phpstan-drupal/extension.neon
  paths:
    - .
    - ../composer

  excludePaths:
    - '*.api.php'
    - 'lib/Drupal/Component/Diff/Engine/*.php'
    - 'modules/migrate_drupal/tests/fixtures/*.php'
    - modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/ExtendingNonInstalledClass.php
    - tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php
    - '../sites/simpletest/*.php'

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?

mondrake’s picture

This also doesn't include phpstan deprecation rules to catch usages of deprecated code. Maybe that's a follow up?

IMHO it should be done here, given we're adding the tools in this issue.

The phpstan.neon.dist is wrong, in my opinion. Why isn't it including the proper extension.neon?

Dunno, can you help? Feel free to push on the fork, BTW

mondrake’s picture

There’s not a phpstan-drupal-deprecations release 1, though, is that right? Latest release is 0.11.1 on packagist.

mglaman’s picture

Yeah, 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.

mglaman’s picture

Another 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...

mglaman’s picture

This one will be hard to debug:

16:57:05  ------ -------------------------------------------------------------------- 
16:57:05   Line   core/modules/views/tests/src/Unit/ViewsTest.php                     
16:57:05  ------ -------------------------------------------------------------------- 
16:57:05          Class Symfony\Contracts\Service\ResetInterface not found.           
16:57:05          💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
16:57:05   11     Class Symfony\Contracts\Service\ResetInterface not found.           
16:57:05          💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
16:57:05  ------ -------------------------------------------------------------------- 

It does not occur for me locally with a clone of the issue fork and composer install:

php vendor/bin/phpstan.phar analyze --configuration ./core/phpstan.neon.dist core/modules/views/tests/src
mondrake’s picture

Out 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:

  1. Internal error: Internal error: assert($type instanceof ObjectType) in file /var/www/html/core/tests/Drupal/Tests/Core/Form/FormStateTest.php Run PHPStan with --debug option and post the stack trace to: https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md
  2. Internal error: Internal error: Cannot assign an empty string to a string offset in file /var/www/html/core/modules/link/tests/src/Kernel/LinkItemTest.php Run PHPStan with --debug option and post the stack trace to: https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md
  3. Internal error: Internal error: assert($type instanceof ObjectType) in file /var/www/html/core/lib/Drupal/Core/Extension/ModuleHandler.php Run PHPStan with --debug option and post the stack trace to: https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md

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:

  • Class Symfony\Contracts\Service\ResetInterface not found.
  • Reflection error: Could not locate constant PDO::FETCH_DEFAULT while trying to evaluate constant expression in Drupal\Core\Database\Statement at line 184
mondrake’s picture

mglaman’s picture

Replicated error for

Internal error: Internal error: assert($type instanceof ObjectType) in file /var/www/html/core/tests/Drupal/Tests/Core/Form/FormStateTest.php
/Users/mglaman/Drupal/sites/drupal-core-dev/core/tests/Drupal/Tests/Core/Form/FormStateTest.php
Uncaught AssertionError: assert($type instanceof ObjectType) in /Users/mglaman/Drupal/sites/drupal-core-dev/vendor/mglaman/phpstan-drupal/src/Rules/Drupal/LoadIncludes.php:57
#0 /Users/mglaman/Drupal/sites/drupal-core-dev/vendor/mglaman/phpstan-drupal/src/Rules/Drupal/LoadIncludes.php(57): assert(false, 'assert($type in...')

It's due to phpstan-drupal code in handling loadIncludes. Opened an issue: https://github.com/mglaman/phpstan-drupal/issues/232

mglaman’s picture

I just released phpstan-drupal:1.0.3 and pushed the update here, which fixes the two assert($type instanceof ObjectType) errors.

mallezie made their first commit to this issue’s fork.

mallezie’s picture

I'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.

Error message "Method Drupal\Core\Routing\AccessAwareRouter::getRouteCollection() should return Symfony\Component\Routing\RouteCollection but return statement is missing." cannot be ignored, use excludePaths  
     instead.                                                                                                                                                                                                         
     Error message "Method Drupal\Core\Routing\AccessAwareRouter::generate() should return string but return statement is missing." cannot be ignored, use excludePaths instead.   
             

#3248859: AccessAwareRouter fails PHPStan-0

     Error message "Method Drupal\FunctionalTests\Bootstrap\ErrorContainer::get() should return object|null but return statement is missing." cannot be ignored, use excludePaths instead.

#3254962: Return type in ErrorContainer

     Error message "Method Drupal\Tests\Component\ProxyBuilder\TestServiceComplexMethod::complexMethod() should return array but return statement is missing." cannot be ignored, use excludePaths instead.           
     Error message "Method Drupal\Tests\Component\ProxyBuilder\TestServiceNullableTypehintSelf::typehintSelf() should return Drupal\Tests\Component\ProxyBuilder\TestServiceNullableTypehintSelf|null but return      
     statement is missing." cannot be ignored, use excludePaths instead.    
     Error message "Method Drupal\Core\File\MimeType\MimeTypeGuesser::guessMimeType() should return string|null but return statement is missing." cannot be ignored, use excludePaths instead.                                                                                                                                                           
     Error message "Method Drupal\Tests\Core\DependencyInjection\Compiler\NewMimeTypeGuesser::guessMimeType() should return string but return statement is missing." cannot be ignored, use excludePaths instead.     
     Error message "Method Drupal\Tests\Core\DependencyInjection\Compiler\NewMimeTypeGuesser::isGuesserSupported() should return bool but return statement is missing." cannot be ignored, use excludePaths instead.  

I included some workarounds for those (which are probably wrong) to have PHPStan working. Issues are created for those.

     Child process error (exit code 255): PHP Fatal error:  Declaration of Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index = null, $constructor_arguments = null) must be compatible with        
     PDOStatement::fetchAll(int $mode = PDO::FETCH_DEFAULT, mixed ...$args) in /app/core/lib/Drupal/Core/Database/Statement.php on line 184                                                                           
     Fatal error: Declaration of Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index = null, $constructor_arguments = null) must be compatible with PDOStatement::fetchAll(int $mode =               
     PDO::FETCH_DEFAULT, mixed ...$args) in /app/core/lib/Drupal/Core/Database/Statement.php on line 184                                                                                                              
                                                                                                                                                                                                                      
     Child process error (exit code 255): PHP Warning:  Undefined property: PhpParser\Node\Stmt\Class_::$namespacedName in /app/vendor/mglaman/phpstan-drupal/src/Rules/Classes/PluginManagerInspectionRule.php on    
     line 31                                                                                                                                                                                                          
     Warning: Undefined property: PhpParser\Node\Stmt\Class_::$namespacedName in /app/vendor/mglaman/phpstan-drupal/src/Rules/Classes/PluginManagerInspectionRule.php on line 31                                      
     PHP Fatal error:  Declaration of Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index = null, $constructor_arguments = null) must be compatible with PDOStatement::fetchAll(int $mode =          
     PDO::FETCH_DEFAULT, mixed ...$args) in /app/core/lib/Drupal/Core/Database/Statement.php on line 184                                                                                                              
     Fatal error: Declaration of Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index = null, $constructor_arguments = null) must be compatible with PDOStatement::fetchAll(int $mode =               
     PDO::FETCH_DEFAULT, mixed ...$args) in /app/core/lib/Drupal/Core/Database/Statement.php on line 184                                                                                                              
                                                                                                                                                                                                                      
     Child process error (exit code 255): PHP Warning:  Undefined array key 0 in /app/vendor/mglaman/phpstan-drupal/src/Rules/Drupal/ModuleLoadInclude.php on line 40                                                 
     Warning: Undefined array key 0 in /app/vendor/mglaman/phpstan-drupal/src/Rules/Drupal/ModuleLoadInclude.php on line 40                                                                                           
     PHP Warning:  Undefined array key 0 in /app/vendor/mglaman/phpstan-drupal/src/Rules/Drupal/LoadIncludes.php on line 50                                                                                           
     Warning: Undefined array key 0 in /app/vendor/mglaman/phpstan-drupal/src/Rules/Drupal/LoadIncludes.php on line 50                                                                                                
     PHP Fatal error:  Declaration of Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index = null, $constructor_arguments = null) must be compatible with PDOStatement::fetchAll(int $mode =          
     PDO::FETCH_DEFAULT, mixed ...$args) in /app/core/lib/Drupal/Core/Database/Statement.php on line 184                                                                                                              
     Fatal error: Declaration of Drupal\Core\Database\Statement::fetchAll($mode = null, $column_index = null, $constructor_arguments = null) must be compatible with PDOStatement::fetchAll(int $mode =               
     PDO::FETCH_DEFAULT, mixed ...$args) in /app/core/lib/Drupal/Core/Database/Statement.php on line 184                                                                                                              

#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

     Internal error: Internal error: Cannot assign an empty string to a string offset in file /app/core/modules/link/tests/src/Kernel/LinkItemTest.php                                                                
     Run PHPStan with --debug option and post the stack trace to:                                                                                                                                                     
     https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md     

#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.

mallezie’s picture

Still 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.

mondrake’s picture

Too many MR branches, now it's hard to follow. Going back to good old patches.

mondrake’s picture

mondrake’s picture

Status: Needs review » Needs work

The last submitted patch, 79: 3178534-79.patch, failed testing. View results

Spokje’s picture

FileSize
2.04 KB
91.48 KB

Patch #79 after running COMPOSER_ROOT_VERSION=10.0.x-dev composer update --lock

Spokje’s picture

Status: Needs work » Needs review
mondrake’s picture

We should update phpstan/phpstan to 1.2.0 and mglaman/phpstan-drupal to 1.1.3

Spokje’s picture

FileSize
6.53 KB
91.32 KB

We should update phpstan/phpstan to 1.2.0 and mglaman/phpstan-drupal to 1.1.3

Attached patch should do just that, and bring composer plugin-api-version back to the original 2.1.0

mondrake’s picture

Try fixing the ErrorContainer issue, that produces errors on PHPStan run

mondrake’s picture

Ignore extending @internal classes.

mondrake’s picture

mglaman’s picture

Ignore extending @internal classes.

Can 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)

mondrake’s picture

mondrake’s picture

Ignore not found classes, and fixes for Statement / StatementEmpty (due to be removed from D19 though).

mondrake’s picture

FileSize
93.76 KB
2.68 KB
mondrake’s picture

FileSize
96.84 KB
3.51 KB

Not found classes cannot be ignored - this becomes a stopper. Added more #[\ReturnTypeWillChange] annotations.

mondrake’s picture

FileSize
3.51 KB
96.84 KB
daffie’s picture

Status: Needs review » Needs work

Patch looks good.

  1. +++ b/core/phpstan.neon.dist
    @@ -0,0 +1,36 @@
    +	- phpstan-baseline.neon
    ...
    +		# @todo files below need to be excluded as they prevent baseline generation.
    +		# Fixing them is a priority.
    

    These lines have tabs.

  2. The file core/phpstan-baseline.neon is full of tabs.
  3. +++ b/core/drupalci.yml
    @@ -6,12 +6,19 @@
    +          - "cd ${SOURCE_DIR}/core && sudo -u www-data ../vendor/bin/phpstan analyze"
    

    Do we really need the part: "sudo -u www-data"?

  4. +++ b/core/drupalci.yml
    @@ -6,12 +6,19 @@
    -        halt-on-fail: true
    +        halt-on-fail: false
    

    This change is out of scope for this issue.

  5. +++ b/core/drupalci.yml
    @@ -6,12 +6,19 @@
    +      # Core's code quality is checked by container_command.commit_checks.
    +      # For testing only, run PHPStan across the entire codebase.
    

    So this part does not need to be committed?

  6. +++ b/core/lib/Drupal/Core/Database/Statement.php
    @@ -21,7 +21,7 @@
    -class Statement extends \PDOStatement implements StatementInterface {
    +class Statement extends \PDOStatement {
    

    Why are we removing the StatementInterface?

  7. +++ b/core/lib/Drupal/Core/Database/Statement.php
    @@ -161,7 +163,7 @@ public function rowCount() {
    -  public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
    +  public function setFetchMode(int $mode, mixed ...$args) {
    
    @@ -170,18 +172,19 @@ public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
    -  public function fetchAll($mode = NULL, $column_index = NULL, $constructor_arguments = NULL) {
    ...
    +  public function fetchAll(int $mode = \PDO::FETCH_DEFAULT, mixed ...$args) {
    

    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?

  8. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Drupal\\\\Core\\\\Http\\\\LinkRelationTypeManager must override __construct if using YAML plugins\\.$#"
    +			count: 1
    +			path: lib/Drupal/Core/Http/LinkRelationTypeManager.php
    

    Can you explain to me why we have this exception here? The class is overriding the method __construct().

  9. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Inner named functions are not supported by PHPStan\\. Consider refactoring to an anonymous function, class method, or a top\\-level\\-defined function\\. See issue \\#165 \\(https\\://github\\.com/phpstan/phpstan/issues/165\\) for more details\\.$#"
    +			count: 2
    +			path: modules/ckeditor5/ckeditor5.module
    

    Can we create a followup issue to fix this problem in PHPStan?

  10. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Call to sprintf contains 1 placeholder, 0 values given\\.$#"
    +			count: 1
    +			path: modules/ckeditor5/src/Controller/CKEditor5ImageController.php
    

    Could we create a followup issue to fix this problem in PHPStan?

  11. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Access to an undefined static property static\\(Drupal\\\\Tests\\\\dblog\\\\Functional\\\\DbLogResourceTest\\)\\:\\:\\$entityTypeId\\.$#"
    +			count: 1
    +			path: modules/dblog/tests/src/Functional/DbLogResourceTest.php
    

    This need to be fixed in core/modules/rest/tests/src/Functional/CookieResourceTestTrait.php.

  12. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Call to an undefined static method static\\(Drupal\\\\Tests\\\\migrate\\\\Kernel\\\\MigrateTestBase\\)\\:\\:migrateDumpAlter\\(\\)\\.$#"
    +			count: 1
    +			path: modules/migrate/tests/src/Kernel/MigrateTestBase.php
    

    This should to be fixed. Can we add the static variable migrateDumpAlter?

  13. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Class Drupal\\\\block\\\\Entity\\\\Block referenced with incorrect case\\: Drupal\\\\block\\\\entity\\\\Block\\.$#"
    +			count: 2
    +			path: modules/settings_tray/settings_tray.module
    

    Can we fix this one. It does not sound very difficult to fix.

  14. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Class Drupal\\\\advisory_feed_test\\\\AdvisoriesTestHttpClient extends @final class GuzzleHttp\\\\Client\\.$#"
    +			count: 1
    +			path: modules/system/tests/modules/advisory_feed_test/src/AdvisoriesTestHttpClient.php
    

    Can we create a followup issue to fix this?

  15. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Result of function usleep \\(void\\) is used\\.$#"
    +			count: 1
    +			path: modules/system/tests/modules/hold_test/src/EventSubscriber/HoldTestSubscriber.php
    

    Can we fix this or create a followup issue for it.

  16. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Instantiated class Drupal\\\\Tests\\\\system\\\\Functional\\\\FileTransfer\\\\Exception not found\\.$#"
    +			count: 1
    +			path: modules/system/tests/src/Functional/FileTransfer/FileTransferTest.php
    

    Can we fix this or create a followup to fix it. This should not be that difficult to fix.

  17. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Undefined variable\\: \\$arg$#"
    +			count: 1
    +			path: modules/views/src/Plugin/views/argument_validator/None.php
    

    Can we fix this. Should not be that difficult.

  18. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Undefined variable\\: \\$def$#"
    +			count: 2
    +			path: modules/views/src/Plugin/views/relationship/EntityReverse.php
    

    Can we fix this. Should be not that difficult.

  19. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Parameter \\$template of method Drupal\\\\KernelTests\\\\KernelTestBase\\:\\:prepareTemplate\\(\\) has invalid type Text_Template\\.$#"
    +			count: 1
    +			path: tests/Drupal/KernelTests/KernelTestBase.php
    

    Can we fix this. Should not be that difficult.

  20. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Result of static method Drupal\\\\Composer\\\\Composer\\:\\:ensureComposerVersion\\(\\) \\(void\\) is used\\.$#"
    +			count: 1
    +			path: tests/Drupal/Tests/Composer/ComposerTest.php
    

    Can we fix this. Should not be that difficult.

  21. +++ b/core/phpstan-baseline.neon
    @@ -0,0 +1,1216 @@
    +			message: "#^Call to an undefined static method PHPUnit\\\\Util\\\\ErrorHandler\\:\\:handleError\\(\\)\\.$#"
    +			count: 1
    +			path: tests/Drupal/Tests/Listeners/DrupalListener.php
    

    Can we fix this or create a followup to fix this.

  22. +++ 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
    

    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.

  23. +++ b/core/phpstan.neon.dist
    @@ -0,0 +1,36 @@
    +    # Ignore common errors for now.
    +    - "#^Access to an undefined property#"
    +    - "#^Call to an undefined method#"
    +    - "#^Cannot unset offset#"
    +    - "#should return .* but return statement is missing#"
    +    - "#Drupal calls should be avoided in classes, use dependency injection instead#"
    +    - "#^Plugin definitions cannot be altered.#"
    +    - "#^Missing cache backend declaration for performance.#"
    +    - "#cache tag might be unclear and does not contain the cache key in it.#"
    +    - "#^Class .* extends @internal class#"
    +    - "#^File .* could not be loaded from module_load_include.#"
    

    Which of the following common error need a followup so that they can be removed?

  24. In the file core/scripts/dev/commit-code-check.sh I am missing the part where the all files are checked when the files core/phpstan.neon.dist and core/phpstan-baseline.neon are changed. Just like we do with core/phpcs.xml.dist.
mondrake’s picture

Thanks for review @daffie, sorry I forgot to change status to NW, this patch is still far from being committable.

The idea is

  • commit a patch with ignores and baseline that can enable running PHPStan level 0 and prevent further level-0 issues to enter the codebase
  • keep to a minimum other code changes
  • 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

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:

  • we still have 29 errors like
    20:00:11  ------ --------------------------------------------------------------------- 
    20:00:11   Line   core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php           
    20:00:11  ------ --------------------------------------------------------------------- 
    20:00:11          Class Symfony\Contracts\Service\ResetInterface not found.            
    20:00:11          💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
    20:00:11  ------ --------------------------------------------------------------------- 
    

    that cannot be ignored nor added to the baseline, so we need to solve upfront

  • +++ 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
    +
    

    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

mondrake’s picture

Forgot 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.

mglaman’s picture

Can you explain to me why we have this exception here? The class is overriding the method __construct().

I 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

Can we create a followup issue to fix this problem in PHPStan?

These all refer to Drupal issues, right?

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.

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.

mondrake’s picture

FileSize
89.83 KB
13.17 KB
mondrake’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update
kim.pepper’s picture

Status: Needs work » Needs review
FileSize
89.52 KB
802 bytes

Updated composer.lock with COMPOSER_ROOT_VERSION=10.0.x-dev composer update --lock

daffie’s picture

Status: Needs review » Needs work

Most of my points from comment #94 still stand.

alexpott’s picture

+++ b/core/scripts/dev/commit-code-check.sh
@@ -283,6 +284,19 @@
+  ############################################################################
+  ### PHPSTAN
+  ############################################################################
+  if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.(inc|install|module|php|profile|test|theme)$ ]]; then
+    vendor/bin/phpstan analyze --no-progress --configuration="$TOP_LEVEL/core/phpstan.neon.dist" "$TOP_LEVEL/$FILE"
+    if [ "$?" -ne "0" ]; then
+      # If there are failures set the status to a number other than 0.
+      STATUS=1
+    else
+      printf "PHPStan: $FILE ${green}passed${reset}\n"
+    fi
+  fi

If 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.

mondrake’s picture

mondrake’s picture

mondrake’s picture

alexpott’s picture

This is looking great.

So now we need to implement a full scan if core/phpstan.neon.dist or core/phpstan-baseline.neon changes.

+++ b/core/phpcs.xml.dist
@@ -24,6 +24,9 @@
+  <!--Exclude rewritten PHPUnit classes.-->
+  <exclude-pattern>./sites/simpletest/*</exclude-pattern>
+
   <!-- Only include specific sniffs that pass. This ensures that, if new sniffs are added, HEAD does not fail.-->

I don't think this needs to be here.

mondrake’s picture

Yes, 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.

mondrake’s picture

FileSize
583 bytes
85.02 KB
mondrake’s picture

FileSize
2.35 KB
85.47 KB
mondrake’s picture

Done #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.

alexpott’s picture

Status: Needs work » Needs review

@mondrake if I run

vendor/bin/phpstan analyze  --configuration=core/phpstan.neon.dist

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.

mondrake’s picture

#111 same here... so it is a DrupalCI problem. Concurrency?

mondrake’s picture

FileSize
85.52 KB
285 bytes

Trying to restrict max number of concurrent processes, see #67

mondrake’s picture

Better. Trying to disable concurrency altogether.

mondrake’s picture

Gosh... different levels of parallelism give different results...

mondrake’s picture

Revert phpcs.xml.dist changes

mondrake’s picture

Taran2L’s picture

Let's try to debug

mglaman’s picture

I'm copying something I shared in Slack with @alexpott.

We should try setting the cache folder to a relative directory:

parameters:
	tmpDir: tmp

Otherwise the temp folder is generated with sys_get_temp_dir(). My concern was this conflicting with other workspaces in Jekins. But @alexpott suggested

What it might be is the temp dir might be a tmpfs dir and maybe we exhaust it and odd things happen - so changing tmp might be a good idea - can we do that on the command line - on the phpstan invocation? I'm afk atm so can't see easily for myself…

We should try setting the tmpDir param and see if it makes things more reliable.

mondrake’s picture

We need to create a temp directory before running PHPStan then? Named like what and where?

alexpott’s picture

Taran2L’s picture

hi @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:

  1. Disables caching
  2. Disables concurrency

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

Taran2L’s picture

Taran2L’s picture

alexpott’s picture

@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.

alexpott’s picture

FileSize
1.16 KB

Here'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.

Taran2L’s picture

@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 ...

alexpott’s picture

Here'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.

alexpott’s picture

#697946: Properly deprecate module_load_include() and move it into \Drupal::moduleHandler() service introduced two new issues to add to baseline...

 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------
  Line   modules/system/tests/modules/entity_test/entity_test.install
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------
  59     File core/modules/system/tests/modules/entity_test/entity_test.inc could not be loaded from Drupal\Core\Extension\ModuleHandlerInterface::loadInclude
  61     File core/modules/system/tests/modules/entity_test/entity_test.inc could not be loaded from Drupal\Core\Extension\ModuleHandlerInterface::loadInclude
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------
Taran2L’s picture

@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?

alexpott’s picture

Sure - this updates all the dependencies added here and updates the baseline to reflect the changes in phpstan-drupal.

alexpott’s picture

We shouldn't be deciding how many processes to run... let's let phpstan do that.

alexpott’s picture

With #131 a run on all the files:

11:09:08 Running PHPStan on *all* files.
11:12:42 
11:12:42  [OK] No errors   

With #132

11:14:35 Running PHPStan on *all* files.
11:15:48 
11:15:48  [OK] No errors   

So that's v nice.

mondrake’s picture

So 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?

alexpott’s picture

@mondrake good point about the ignoreErrors... the private call thing in tests is bogus anyway.

mondrake’s picture

Status: Needs review » Needs work
+++ b/composer.json
@@ -34,7 +34,10 @@
+        "phpstan/phpstan": "^1.2",
+        "mglaman/phpstan-drupal": "^1.1.3",

IMHO we should commit with composer.json constraints in line with the version we are actually starting using

alexpott’s picture

Status: Needs work » Needs review
FileSize
2.38 KB
113.42 KB

Sure why not. tbh the whole dev dependency pinning and locks is all interesting.

alexpott’s picture

+++ b/core/phpstan-baseline.neon
@@ -0,0 +1,1752 @@
+		-
+			message: "#^\\#pre_render callback class 'static\\(Drupal\\\\Core\\\\Render\\\\Element\\\\Button\\)' at key '0' does not implement Drupal\\\\Core\\\\Security\\\\TrustedCallbackInterface\\.$#"
+			count: 1
+			path: lib/Drupal/Core/Render/Element/Button.php
+

These reports are not correct. Opened https://github.com/mglaman/phpstan-drupal/pull/292 to deal with this.

mallezie’s picture

reportUnmatchedIgnoredErrors: false

Should that be in the phpstan config?
Having this removed always forces a clean baseline, which we should strive for?

mglaman’s picture

I 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.

mglaman’s picture

Also:

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

alexpott’s picture

Updating things again.

mglaman’s picture

+++ b/core/scripts/dev/commit-code-check.sh
@@ -126,6 +131,10 @@
+  if [[ $FILE == "core/phpstan-baseline.neon" || $FILE == "core/phpstan.neon.dist" ]]; then
+    PHPSTAN_DIST_FILE_CHANGED=1;
+  fi;

@@ -181,6 +190,28 @@
+if [[ $PHPSTAN_DIST_FILE_CHANGED == "1" ]]; then
+  printf "\nRunning PHPStan on *all* files.\n"
+  php -d apc.enabled=0 -d apc.enable_cli=0 vendor/bin/phpstan analyze --no-progress --configuration="$TOP_LEVEL/core/phpstan.neon.dist"
+else
+  printf "\nRunning PHPStan on changed files.\n"
+  php -d apc.enabled=0 -d apc.enable_cli=0 vendor/bin/phpstan analyze --no-progress --configuration="$TOP_LEVEL/core/phpstan.neon.dist" $ABS_FILES
+fi

This 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.

alexpott’s picture

@mglaman I think we can get the best of both worlds.

alexpott’s picture

Now with commentary to explain what's going on.

cmlara’s picture

Expanding 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)

Taran2L’s picture

mglaman’s picture

@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.

mondrake’s picture

mondrake’s picture

@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.

Taran2L’s picture

@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:

 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------- 
  Line   core/modules/field_ui/tests/src/Kernel/FieldUiRouteEnhancerTest.php                                                                                    
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------- 
  27     The "%alias_id%" service is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. Use the "route_enhancer.entity_bundle" service instead. See  
         https://www.drupal.org/node/3245017                                                                                                                    
 ------ ------------------------------------------------------------------------------------------------------------------------------------------------------- 

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)

  1. modules/migrate_drupal/tests/fixtures/drupal6.php
  2. modules/migrate_drupal/tests/fixtures/drupal7.php

PHPStan also support a newer way of excluding files:

parameters:
    excludePaths:
        analyse:
            - src/thirdparty
        analyseAndScan:
            - src/broken

So, this issue raises 2 questions here:

  1. Should we update files exclusion rules in the phpstan-drupal plugin to be more precise and use the new phpstan options?
  2. Should Drupal gzip such DB dump fixtures files by default, as it does in some places like https://git.drupalcode.org/project/drupal/-/blob/9.4.x/core/modules/syst...? Maybe just rename to something like *.php.data. Should we create a follow-up for this?

4. Baseline file uses tabs

Seems like we cannot do anything with that, right?

5. Rule RenderCallbackRule generates too much false positives

Let's maybe disable it for now?

Taran2L’s picture

OK, new patch addressing issue with LinkItemTest only

mglaman’s picture

For PHPStan currently we require: drupal extension + extension loader + phpstan (tool)
But for PHPCS we require: drupal extension only

phpstan-drupal does not have a strict requirement. PHPStan moves fast. It makes sense to pin to a specific PHPStan here.

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?

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.

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)

I don't think phpstan-drupal has these excludes in it's config. That's drupal-check

Let's maybe disable it for now?

You can't.

OK, new patch addressing issue with LinkItemTest only

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

Taran2L’s picture

phpstan-drupal does not have a strict requirement. PHPStan moves fast. It makes sense to pin to a specific PHPStan here.

OK, makes sense

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.

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 don't think phpstan-drupal has these excludes in it's config. That's drupal-check

I think it is https://github.com/mglaman/phpstan-drupal/blob/main/extension.neon#L6

You can't.

Oh :( I guess this is a PHPStan limitation. Major one tbh (not blocking us from using it of course)

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

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]

mondrake’s picture

@Taran2L

But this patch before my changes has a lot of code changes in order to PHPStan to work.

Please read the issue summary, it says

in this issue, keep to a minimum other code changes - i.e. only those without which PHPStan execution would crash

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.

alexpott’s picture

Back 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.

alexpott’s picture

Issue summary: View changes

Added 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.

alexpott’s picture

Opened https://github.com/mglaman/phpstan-drupal/pull/297 to put mglaman/phpstan-drupal on a dependency diet :)

alexpott’s picture

Issue summary: View changes

Added dependency evaluation for webflo's drupal-finder

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

With 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.

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs review
Issue tags: +10.0.0 release notes, +10.0.0 release highlights

@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:

  • Land the upstream fix to have less dependencies
  • Add a change record that details how to run the checks as a core developer
  • Add a release note to the issue summary that announces the change for 10.0.0

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.

alexpott’s picture

The upstream fix to not use nette/finder has landed and been released - thanks @mglaman.

So now the dependency evaluations are complete.

mondrake’s picture

Wow that was fast!

daffie’s picture

Status: Needs review » Needs work
+++ b/core/scripts/dev/commit-code-check.sh
@@ -110,6 +111,10 @@
+# This variable will be set to one when the files core/phpstan-baseline.neon or
+# core/phpstan.neon.dist are changed.
+PHPSTAN_DIST_FILE_CHANGED=0

@@ -126,6 +131,10 @@
+  if [[ $FILE == "core/phpstan-baseline.neon" || $FILE == "core/phpstan.neon.dist" ]]; then
+    PHPSTAN_DIST_FILE_CHANGED=1;
+  fi;

Should 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:

  if [[ $FILE == "core/phpstan-baseline.neon" || $FILE == "core/phpstan.neon.dist" ]]; then
    PHPSTAN_DIST_FILE_CHANGED=1;
  fi;
longwave’s picture

Status: Needs work » Needs review

> 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.

daffie’s picture

All 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!

daffie’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

Added the missing CR.
The patch was for me already RTBC.
Changing the status to RTBC for the release manager review.

catch’s picture

The 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.

xjm’s picture

Thanks 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).

xjm’s picture

Meant to tag.

neclimdul’s picture

Its 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...

alexpott’s picture

@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.

alexpott’s picture

FWIW 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.

neclimdul’s picture

Status: Reviewed & tested by the community » Needs review

Didn'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.

  1. Only looking at the core neon files ignores changes to included neon files so it wouldn't trigger a full run based on new rules from phpstan or drupalstan. That blocks us out of running checks for new language features or improved static checks on the entire code base without hacks.
  2. Running partial checks means we never know the affects of that change on the rest of the code base. This is one of the key benefits of static analysis.
  3. We never see the full scan so each change to phpstan.neon becomes a "fix all the things" exercise as the code base drifts away from the baseline.

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.

neclimdul’s picture

@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.

mglaman’s picture

I am going to echo that the following scares me:

  if [[ $FILE == "core/phpstan-baseline.neon" || $FILE == "core/phpstan.neon.dist" ]]; then
    PHPSTAN_DIST_FILE_CHANGED=1;
  fi;

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.)

alexpott’s picture

Status: Needs review » Reviewed & tested by the community

Re #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.

alexpott’s picture

I've added the CLI commands to regenerate the baseline to the CR - https://www.drupal.org/node/3258232

neclimdul’s picture

I'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.

alexpott’s picture

@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.

alexpott’s picture

Updated phpstan-drupal to get the benefits of @mglaman's work on the render callback rule.

mglaman’s picture

it's wanting the additional cost to be justified.

True, that makes sense. Let's just see where it goes. We're better off than we were before.

+1 on adding to the CR

mglaman’s picture

FYI 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

message: "#^The \"\\#lazy_builder\" expects a callable array with arguments\\.$#"

Glad to see 1.1.8 resolved the erroneous callback errors I generated in 1.1.5

mondrake’s picture

Assigned: Unassigned » mondrake
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll

Working on this

mondrake’s picture

After upgrading to Symfony 5.4 we now have a problem upstream:

  Problem 1
    - mglaman/phpstan-drupal is locked to version 1.1.8 and an update of this package was not requested.
    - mglaman/phpstan-drupal 1.1.8 requires symfony/finder ~3.4.5|^4.2 -> found symfony/finder[v5.4.2] but it does not match the constraint.
mondrake’s picture

Assigned: mondrake » Unassigned
mglaman’s picture

Can you open an issue on phpstan-drupal to bump the dependency upper constraint

mondrake’s picture

mglaman’s picture

mondrake’s picture

Assigned: Unassigned » mondrake

Rerolling.

alexpott’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Reviewed & tested by the community
FileSize
2.72 KB
75.37 KB

Re-rolled with the new version.

diff --git a/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php b/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php
index ef3dd8670f..d2d7287557 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php
@@ -298,14 +298,14 @@ public function isGroupValidated($cache_key, $group_hash): bool {
    * {@inheritdoc}
    */
   public function markObjectAsInitialized($cache_key) {
-    // Not supported, so nothing todo.
+    throw new \LogicException('\Symfony\Component\Validator\Context\ExecutionContextInterface::markObjectAsInitialized is unsupported.');
   }

   /**
    * {@inheritdoc}
    */
   public function isObjectInitialized($cache_key): bool {
-    // Not supported, so nothing todo.
+    throw new \LogicException('\Symfony\Component\Validator\Context\ExecutionContextInterface::isObjectInitialized is unsupported.');
   }

   /**

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.

mondrake’s picture

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.

+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.

mondrake’s picture

Issue tags: -Needs reroll
catch’s picture

Still 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?

mondrake’s picture

#195

Not sure exactly how we'll run down all the exclusions we're adding...

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.

alexpott’s picture

I've addressed the request for documentation updates in #171 - see https://www.drupal.org/about/core/policies/core-dependency-policies/core...

mallezie’s picture

Great 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.

  • catch committed fe307a0 on 10.0.x
    Issue #3178534 by mondrake, klausi, alexpott, longwave, mallezie,...
catch’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed

I 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.

Taran2L’s picture

@catch, that's weird .. it takes ~3-4m on my Late 2016 MacBook Pro, maybe on pre-commit it runs in 1 thread, weird

mondrake’s picture

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.

I 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.

neclimdul’s picture

fwiw, took about 2 min for me or approximately one functional tests with 10-12 tests.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.