From 11a92f4a7d92f49868141ba76de8c0f81f26fe47 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 13:26:15 +0100 Subject: [PATCH 1/9] [Code] Reworked \mglaman\PHPStanDrupal\Drupal\ExtensionMap::keyByExtensionName --- src/Drupal/ExtensionMap.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Drupal/ExtensionMap.php b/src/Drupal/ExtensionMap.php index 819c23b0..b45b59c2 100644 --- a/src/Drupal/ExtensionMap.php +++ b/src/Drupal/ExtensionMap.php @@ -74,14 +74,8 @@ public function setExtensions(array $modules, array $themes, array $profiles): v */ private static function keyByExtensionName(array $extensions): array { - // PHP 7.4 returns array|false, PHP 8.0 only returns an array. - // Make PHPStan happy. When PHP 7.4 is dropped, reduce to a single - // return. - $combined = array_combine(array_map(static function (Extension $extension) { + return array_combine(array_map(static function (Extension $extension) { return $extension->getName(); }, $extensions), $extensions); - // @phpstan-ignore-next-line - assert(is_array($combined)); - return $combined; } } From e0b81158725c1dca1f9efded39f4cab202298a7f Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 13:27:14 +0100 Subject: [PATCH 2/9] [HACK] Temporarily remove core_baseline test --- .github/workflows/php.yml | 55 --------------------------------------- 1 file changed, 55 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ccf15bcb..8fc31229 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -203,58 +203,3 @@ jobs: run: | cd ~/drupal ./vendor/bin/phpstan analyze web/core/modules/dynamic_page_cache --debug - - core_baseline: - needs: - - lint - - tests - continue-on-error: true - runs-on: "ubuntu-latest" - name: "Drupal core HEAD baseline check" - steps: - - name: "Checkout" - uses: "actions/checkout@v4" - - name: "set the version alias for self" - run: | - if [ "${{ github.event_name }}" == 'pull_request' ]; then - echo "VERSION_ALIAS=dev-"${{ github.sha }}"" >> $GITHUB_OUTPUT - else - echo "VERSION_ALIAS=dev-main" >> $GITHUB_OUTPUT - fi - id: branch_alias - - name: determine phpstan cache directory - run: echo PHPSTAN_TMP_DIR=$(php -r "print sys_get_temp_dir() . '/phpstan';") >> $GITHUB_OUTPUT - id: phpstan_tmp_dir - - name: cache phpstan - uses: actions/cache@v4 - with: - path: ${{ steps.phpstan_tmp_dir.outputs.PHPSTAN_TMP_DIR }} - key: ${{ runner.os }}-phpstan-core-baseline - restore-keys: ${{ runner.os }}-phpstan-core-baseline - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "8.3" - tools: composer:v2 - extensions: dom, curl, libxml, mbstring, zip, pdo, mysql, pdo_mysql, gd, apcu - - name: "Checkout Drupal core" - run: | - cd ${{ runner.temp }} - git clone https://git.drupalcode.org/project/drupal.git - cd drupal - composer config repositories.0 composer https://packages.drupal.org/8 - composer config repositories.1 path $GITHUB_WORKSPACE - - - name: "Install Drupal core dependencies" - uses: "ramsey/composer-install@v3" - with: - working-directory: "${{ runner.temp }}/drupal" - - name: "require phpstan-drupal" - run: | - cd ${{ runner.temp }}/drupal - composer require drupal/core-dev "phpstan/phpstan:^2.0" "phpstan/phpstan-phpunit:^2.0" mglaman/phpstan-drupal "${{ steps.branch_alias.outputs.VERSION_ALIAS }} as 2.99.99" phpstan/extension-installer --with-all-dependencies - - name: "Check baseline" - run: | - cd ${{ runner.temp }}/drupal - ./vendor/bin/phpstan analyze --configuration=core/phpstan.neon.dist From b56b558bbfde08bca610784376256e9af07731df Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 14:16:37 +0100 Subject: [PATCH 3/9] [Code] Reworked \mglaman\PHPStanDrupal\Drupal\ExtensionMap::keyByExtensionName --- src/Drupal/ExtensionMap.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Drupal/ExtensionMap.php b/src/Drupal/ExtensionMap.php index b45b59c2..ff788b06 100644 --- a/src/Drupal/ExtensionMap.php +++ b/src/Drupal/ExtensionMap.php @@ -4,7 +4,6 @@ use function array_combine; use function array_map; -use function is_array; final class ExtensionMap { From 21eed9831f7f565ed740efad8bebe82f537ff5d9 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 14:42:38 +0100 Subject: [PATCH 4/9] [Code] State these @phpstan-ignore-next-line have to stay --- .../Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php | 1 + .../Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php b/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php index 20a28bb4..45eb8499 100644 --- a/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php +++ b/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php @@ -49,6 +49,7 @@ public function processNode(Node $node, Scope $scope): array return []; } + // The next line is intentionally not using [at]phpstan-ignore [identifier]. // @phpstan-ignore-next-line $cmfRouteObjectInterfaceType = new ObjectType(SymfonyRouteObjectInterface::class); if (!$classType->isSuperTypeOf($cmfRouteObjectInterfaceType)->yes()) { diff --git a/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php b/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php index 16981c53..cd39ebbf 100644 --- a/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php +++ b/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php @@ -39,6 +39,7 @@ public function processNode(Node $node, Scope $scope): array } $method = $node->getMethodReflection(); + // The next lines are intentionally not using [at]phpstan-ignore [identifier]. // @phpstan-ignore-next-line $cmfRouteObjectInterfaceType = new ObjectType(RouteObjectInterface::class); // @phpstan-ignore-next-line From 73c7eff3079eca3a36cb84aa413629e67c1327f9 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 14:44:06 +0100 Subject: [PATCH 5/9] [Code] Remov eBC for PHP-Parser 4.x. --- src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php b/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php index 08c8dd50..daf35ef1 100644 --- a/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php +++ b/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php @@ -46,8 +46,7 @@ public function processNode(Node $node, Scope $scope): array // Do some cheap preflight tests to make sure the class is in a // namespace that makes sense to inspect. - // @phpstan-ignore-next-line - $parts = method_exists($node->namespacedName, 'getParts') ? $node->namespacedName->getParts() : $node->namespacedName->parts; + $parts = $node->namespacedName->getParts(); // The namespace is too short to be a test so skip inspection. if (count($parts) < 3) { return []; From 926297447c217a3d9db96e847e57be276156ec16 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 14:45:14 +0100 Subject: [PATCH 6/9] [Code] Remove BC for PHP-Parser 4.x. --- src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php b/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php index daf35ef1..ca64cede 100644 --- a/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php +++ b/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php @@ -12,7 +12,6 @@ use function count; use function in_array; use function interface_exists; -use function method_exists; use function substr_compare; /** From 2e6774e72ddc1a09d656af94c1374a3791a23b58 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 15:12:55 +0100 Subject: [PATCH 7/9] [Code] Go wild and add an explanation why we want to keep the @phpstan-ignore-next-line in these cases --- .../SymfonyCmfRouteObjectInterfaceConstantsRule.php | 2 ++ .../SymfonyCmfRoutingInClassMethodSignatureRule.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php b/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php index 45eb8499..9acfe0c5 100644 --- a/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php +++ b/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php @@ -50,6 +50,8 @@ public function processNode(Node $node, Scope $scope): array } // The next line is intentionally not using [at]phpstan-ignore [identifier]. + // The identifier would be 'class.notFound', which would not be true in + // case of a D9 scan and thus would fail the 'phpstan analyze' phase. // @phpstan-ignore-next-line $cmfRouteObjectInterfaceType = new ObjectType(SymfonyRouteObjectInterface::class); if (!$classType->isSuperTypeOf($cmfRouteObjectInterfaceType)->yes()) { diff --git a/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php b/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php index cd39ebbf..da750ba4 100644 --- a/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php +++ b/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php @@ -40,6 +40,8 @@ public function processNode(Node $node, Scope $scope): array $method = $node->getMethodReflection(); // The next lines are intentionally not using [at]phpstan-ignore [identifier]. + // The identifier would be 'class.notFound', which would not be true in + // case of a D9 scan and thus would fail the 'phpstan analyze' phase. // @phpstan-ignore-next-line $cmfRouteObjectInterfaceType = new ObjectType(RouteObjectInterface::class); // @phpstan-ignore-next-line From 331a5a3afad0666244c66576c162c0347f11f801 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 18:08:41 +0100 Subject: [PATCH 8/9] [Code] More replacements --- src/Type/EntityQuery/EntityQueryType.php | 4 ++-- tests/src/DrushIntegrationTest.php | 2 +- .../EntityFieldMethodsViaMagicReflectionExtensionTest.php | 2 +- .../EntityFieldsViaMagicReflectionExtensionTest.php | 8 ++++---- tests/src/Rules/AccessCheckImpossibleTypeCallRuleTest.php | 6 ++---- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Type/EntityQuery/EntityQueryType.php b/src/Type/EntityQuery/EntityQueryType.php index f8952bd4..f8ab5b45 100644 --- a/src/Type/EntityQuery/EntityQueryType.php +++ b/src/Type/EntityQuery/EntityQueryType.php @@ -27,7 +27,7 @@ public function withAccessCheck(): self { // The constructor of ObjectType is under backward compatibility promise. // @see https://phpstan.org/developing-extensions/backward-compatibility-promise - // @phpstan-ignore-next-line + // @phpstan-ignore new.static $type = new static( $this->getClassName(), $this->getSubtractedType(), @@ -40,7 +40,7 @@ public function withAccessCheck(): self public function asCount(): self { - // @phpstan-ignore-next-line + // @phpstan-ignore new.static $type = new static( $this->getClassName(), $this->getSubtractedType(), diff --git a/tests/src/DrushIntegrationTest.php b/tests/src/DrushIntegrationTest.php index 2c4c288d..c49f6970 100644 --- a/tests/src/DrushIntegrationTest.php +++ b/tests/src/DrushIntegrationTest.php @@ -9,7 +9,7 @@ final class DrushIntegrationTest extends DrupalRuleTestCase protected function getRule(): \PHPStan\Rules\Rule { - // @phpstan-ignore-next-line + // @phpstan-ignore phpstanApi.constructor return new CallToNonExistentFunctionRule( $this->createReflectionProvider(), true diff --git a/tests/src/Reflection/EntityFieldMethodsViaMagicReflectionExtensionTest.php b/tests/src/Reflection/EntityFieldMethodsViaMagicReflectionExtensionTest.php index 431c8c74..d4d88251 100644 --- a/tests/src/Reflection/EntityFieldMethodsViaMagicReflectionExtensionTest.php +++ b/tests/src/Reflection/EntityFieldMethodsViaMagicReflectionExtensionTest.php @@ -47,7 +47,7 @@ public static function dataHasMethod(): \Generator // A content entity for sure does not have this method. yield 'Content entity: referencedEntities' => [ - // @phpstan-ignore-next-line + // @phpstan-ignore class.notFound EntityTest::class, 'referencedEntities', false, diff --git a/tests/src/Reflection/EntityFieldsViaMagicReflectionExtensionTest.php b/tests/src/Reflection/EntityFieldsViaMagicReflectionExtensionTest.php index df5093a8..ed8790d5 100644 --- a/tests/src/Reflection/EntityFieldsViaMagicReflectionExtensionTest.php +++ b/tests/src/Reflection/EntityFieldsViaMagicReflectionExtensionTest.php @@ -43,19 +43,19 @@ public function testHasProperty(string $class, string $property, bool $result): public static function dataHasProperty(): \Generator { yield 'content entity supported' => [ - // @phpstan-ignore-next-line + // @phpstan-ignore class.notFound EntityTest::class, 'foobar', true ]; yield 'config entity not supported' => [ - // @phpstan-ignore-next-line + // @phpstan-ignore class.notFound TestConfigType::class, 'foobar', false ]; yield 'annotated properties are skipped on content entities' => [ - // @phpstan-ignore-next-line + // @phpstan-ignore class.notFound ReflectionEntityTest::class, 'user_id', false @@ -92,7 +92,7 @@ public static function dataHasProperty(): \Generator public function testGetPropertyEntity(): void { - // @phpstan-ignore-next-line + // @phpstan-ignore class.notFound $classReflection = $this->createReflectionProvider()->getClass(EntityTest::class); $propertyReflection = $this->extension->getProperty($classReflection, 'field_myfield'); $readableType = $propertyReflection->getReadableType(); diff --git a/tests/src/Rules/AccessCheckImpossibleTypeCallRuleTest.php b/tests/src/Rules/AccessCheckImpossibleTypeCallRuleTest.php index fe86290e..66040c5f 100644 --- a/tests/src/Rules/AccessCheckImpossibleTypeCallRuleTest.php +++ b/tests/src/Rules/AccessCheckImpossibleTypeCallRuleTest.php @@ -14,20 +14,18 @@ final class AccessCheckImpossibleTypeCallRuleTest extends DrupalRuleTestCase protected function getRule(): Rule { - // @phpstan-ignore-next-line + // @phpstan-ignore phpstanApi.constructor return new ImpossibleCheckTypeMethodCallRule( - // @phpstan-ignore-next-line + // @phpstan-ignore phpstanApi.constructor new ImpossibleCheckTypeHelper( $this->createReflectionProvider(), $this->getTypeSpecifier(), [], false, - true, ), true, false, false, - false, ); } From 81e222a6559aef1b61889e40c8f9a7b8886a6a73 Mon Sep 17 00:00:00 2001 From: Frank Ebbers Date: Fri, 15 Nov 2024 18:08:52 +0100 Subject: [PATCH 9/9] Revert "[HACK] Temporarily remove core_baseline test" This reverts commit e0b81158725c1dca1f9efded39f4cab202298a7f. --- .github/workflows/php.yml | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 8fc31229..ccf15bcb 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -203,3 +203,58 @@ jobs: run: | cd ~/drupal ./vendor/bin/phpstan analyze web/core/modules/dynamic_page_cache --debug + + core_baseline: + needs: + - lint + - tests + continue-on-error: true + runs-on: "ubuntu-latest" + name: "Drupal core HEAD baseline check" + steps: + - name: "Checkout" + uses: "actions/checkout@v4" + - name: "set the version alias for self" + run: | + if [ "${{ github.event_name }}" == 'pull_request' ]; then + echo "VERSION_ALIAS=dev-"${{ github.sha }}"" >> $GITHUB_OUTPUT + else + echo "VERSION_ALIAS=dev-main" >> $GITHUB_OUTPUT + fi + id: branch_alias + - name: determine phpstan cache directory + run: echo PHPSTAN_TMP_DIR=$(php -r "print sys_get_temp_dir() . '/phpstan';") >> $GITHUB_OUTPUT + id: phpstan_tmp_dir + - name: cache phpstan + uses: actions/cache@v4 + with: + path: ${{ steps.phpstan_tmp_dir.outputs.PHPSTAN_TMP_DIR }} + key: ${{ runner.os }}-phpstan-core-baseline + restore-keys: ${{ runner.os }}-phpstan-core-baseline + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "8.3" + tools: composer:v2 + extensions: dom, curl, libxml, mbstring, zip, pdo, mysql, pdo_mysql, gd, apcu + - name: "Checkout Drupal core" + run: | + cd ${{ runner.temp }} + git clone https://git.drupalcode.org/project/drupal.git + cd drupal + composer config repositories.0 composer https://packages.drupal.org/8 + composer config repositories.1 path $GITHUB_WORKSPACE + + - name: "Install Drupal core dependencies" + uses: "ramsey/composer-install@v3" + with: + working-directory: "${{ runner.temp }}/drupal" + - name: "require phpstan-drupal" + run: | + cd ${{ runner.temp }}/drupal + composer require drupal/core-dev "phpstan/phpstan:^2.0" "phpstan/phpstan-phpunit:^2.0" mglaman/phpstan-drupal "${{ steps.branch_alias.outputs.VERSION_ALIAS }} as 2.99.99" phpstan/extension-installer --with-all-dependencies + - name: "Check baseline" + run: | + cd ${{ runner.temp }}/drupal + ./vendor/bin/phpstan analyze --configuration=core/phpstan.neon.dist