diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 0cde952c..24f82558 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -5,15 +5,14 @@ on: jobs: tests: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: fail-fast: false matrix: - os: [ubuntu-latest] - php: [8.0, 8.1, 8.2, 8.3] + php: ["8.0", "8.1", "8.2", "8.3", "8.4"] dependency-versions: [lowest, highest] - name: Tests - P${{ matrix.php }} - ${{ matrix.dependency-versions }} - ${{ matrix.os }} + name: Tests - PHP ${{ matrix.php }} - ${{ matrix.dependency-versions }} steps: - uses: actions/checkout@v4 @@ -41,10 +40,10 @@ jobs: strategy: fail-fast: false matrix: - php: [8.0, 8.1, 8.2, 8.3] + php: ["8.0", "8.1", "8.2", "8.3", "8.4"] dependency-versions: [lowest, highest] - name: Static Analysis - P${{ matrix.php }} - ${{ matrix.dependency-versions }} + name: Static Analysis - PHP ${{ matrix.php }} - ${{ matrix.dependency-versions }} steps: - uses: actions/checkout@v4 diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index c2c3d500..a274cc24 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -1,16 +1,12 @@ in(__DIR__) ->name('*.php') ->notPath('vendor') ->notPath('tests/Enums/Annotate') // Generated ->notPath('tests/Enums/AnnotateFixtures') // Matches laminas/laminas-code - ->notPath('tests/Enums/ToNative') // Generated - ->notPath('tests/Enums/ToNativeFixtures') // Matches laminas/laminas-code ->ignoreDotFiles(false) ->ignoreVCS(true); -return risky($finder); +return MLL\PhpCsFixerConfig\risky($finder); diff --git a/CHANGELOG.md b/CHANGELOG.md index a5555a5e..214dc832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 6.12.0 + +### Added + +- Support Laravel 11 +- Support Rector 2 + ## 6.11.1 ### Fixed diff --git a/Makefile b/Makefile index fa5f9922..e65c5c54 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ it: fix stan test docs ## Run the commonly used targets .PHONY: help help: ## Displays this list of targets with descriptions - @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' + @grep --extended-regexp '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: fix fix: vendor ## Apply automatic code fixes diff --git a/composer.json b/composer.json index 2a7819b0..fab85626 100644 --- a/composer.json +++ b/composer.json @@ -26,25 +26,25 @@ "require": { "php": "^8", "composer/class-map-generator": "^1", - "illuminate/contracts": "^9 || ^10 || ^11", - "illuminate/support": "^9 || ^10 || ^11", + "illuminate/contracts": "^9 || ^10 || ^11 || ^12", + "illuminate/support": "^9 || ^10 || ^11 || ^12", "laminas/laminas-code": "^3.4 || ^4", "nikic/php-parser": "^4.13.2 || ^5" }, "require-dev": { - "doctrine/dbal": "^3.4", - "ergebnis/composer-normalize": "^2.28.3", - "larastan/larastan": "^2.6.3", - "mll-lab/php-cs-fixer-config": "^5.4", - "mockery/mockery": "^1.5", - "orchestra/testbench": "^7.6.1 || ^8 || ^9", - "phpstan/extension-installer": "^1", - "phpstan/phpstan": "^1.8.2", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-phpunit": "^1.1.1", - "phpunit/phpunit": "^9.5.21 || ^10 || ^11", - "rector/rector": "^1", - "symplify/rule-doc-generator": "^11 || ^12 || ^13" + "doctrine/dbal": "^3.9.4", + "ergebnis/composer-normalize": "^2.45", + "larastan/larastan": "^2.9.14 || ^3.1", + "mll-lab/php-cs-fixer-config": "^5.10", + "mockery/mockery": "^1.6.12", + "orchestra/testbench": "^7.6.1 || ^8.33 || ^9.11 || ^10", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.19 || ^2.1.6", + "phpstan/phpstan-mockery": "^1.1.3 || ^2", + "phpstan/phpstan-phpunit": "^1.4.2 || ^2.0.4", + "phpunit/phpunit": "^9.5.21 || ^10.5.45 || ^11.5.10 || ^12.0.5", + "rector/rector": "^1.2.10 || ^2.0.9", + "symplify/rule-doc-generator": "^11.2 || ^12.2.5" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/phpstan.neon b/phpstan.neon index 8dc29ac3..91bfe341 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,6 +8,7 @@ parameters: checkOctaneCompatibility: true reportUnmatchedIgnoredErrors: false # As long as we support multiple Laravel versions at once, there will be some dead spots treatPhpDocTypesAsCertain: false + noEnvCallsOutsideOfConfig: false ignoreErrors: - '#Unsafe usage of new static.*#' # This is a library, so it should be extendable # The Process API is only available in newer Laravel versions @@ -16,7 +17,6 @@ parameters: - '#invalid type Illuminate\\Process#' - '#^Attribute class PHPUnit\\Framework\\Attributes\\DataProvider does not exist\.$#' # Only available with newer PHPUnit versions excludePaths: - - tests/Enums/ToNativeFixtures # Fails with PHP < 8.1 - tests/PHPStan/Fixtures # Install https://plugins.jetbrains.com/plugin/7677-awesome-console to make those links clickable editorUrl: '%%relFile%%:%%line%%' diff --git a/src/Commands/EnumAnnotateCommand.php b/src/Commands/EnumAnnotateCommand.php index e8dcaa10..b3c46f31 100644 --- a/src/Commands/EnumAnnotateCommand.php +++ b/src/Commands/EnumAnnotateCommand.php @@ -75,7 +75,7 @@ protected function annotateFolder(): void } } - /** @param \ReflectionClass<\BenSampo\Enum\Enum> $reflectionClass */ + /** @param \ReflectionClass<*> $reflectionClass */ protected function annotate(\ReflectionClass $reflectionClass): void { $docBlock = $this->getDocBlock($reflectionClass); @@ -111,7 +111,7 @@ protected function annotate(\ReflectionClass $reflectionClass): void $this->info("Wrote new phpDocBlock to {$fileName}."); } - /** @param \ReflectionClass<\BenSampo\Enum\Enum> $reflectionClass */ + /** @param \ReflectionClass<*> $reflectionClass */ protected function getDocBlock(\ReflectionClass $reflectionClass): DocBlockGenerator { $docBlock = DocBlockGenerator::fromArray([]) @@ -145,7 +145,7 @@ protected function getDocblockWithoutTags(DocBlockReflection $docBlockReflection } /** - * @param \ReflectionClass<\BenSampo\Enum\Enum> $reflectionClass + * @param \ReflectionClass<*> $reflectionClass * * @return array<\Laminas\Code\Generator\DocBlock\Tag\TagInterface> */ diff --git a/src/Enum.php b/src/Enum.php index 6f1c9964..44991c8c 100644 --- a/src/Enum.php +++ b/src/Enum.php @@ -85,7 +85,7 @@ public static function fromValue(mixed $enumValue): static return $enumValue; } - return new static($enumValue); + return new static($enumValue); // @phpstan-ignore return.type (generic variance) } /** diff --git a/src/PHPStan/UniqueValuesRule.php b/src/PHPStan/UniqueValuesRule.php index 8841f289..e1383dc7 100644 --- a/src/PHPStan/UniqueValuesRule.php +++ b/src/PHPStan/UniqueValuesRule.php @@ -35,17 +35,18 @@ public function processNode(Node $node, Scope $scope): array foreach ($constants as $name => $value) { $constantsWithValue = array_filter($constants, fn (mixed $v): bool => $v === $value); if (count($constantsWithValue) > 1) { - $duplicateConstants[] = array_keys($constantsWithValue); + $duplicateConstants[] = json_encode(array_keys($constantsWithValue)); } } $duplicateConstants = array_unique($duplicateConstants); if (count($duplicateConstants) > 0) { $fqcn = $reflection->getName(); - $constantsString = json_encode($duplicateConstants); + $constantsString = implode(',', $duplicateConstants); return [ RuleErrorBuilder::message("Enum class {$fqcn} contains constants with duplicate values: {$constantsString}.") + ->identifier('enum.duplicateValues') ->build(), ]; } diff --git a/src/Rector/ToNativeUsagesRector.php b/src/Rector/ToNativeUsagesRector.php index 58e2d122..f99a7a5a 100644 --- a/src/Rector/ToNativeUsagesRector.php +++ b/src/Rector/ToNativeUsagesRector.php @@ -50,6 +50,7 @@ use PhpParser\Node\Stmt\Switch_; use PhpParser\Node\VariadicPlaceholder; use PHPStan\Type\ObjectType; +use PHPStan\Node\Expr\AlwaysRememberedExpr; use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -664,6 +665,9 @@ protected function refactorKey(PropertyFetch $fetch): ?Node protected function refactorMatch(Match_ $match): ?Node { $cond = $match->cond; + while ($cond instanceof AlwaysRememberedExpr) { // @phpstan-ignore phpstanApi.class (backwards compatibility not guaranteed) + $cond = $cond->getExpr(); // @phpstan-ignore phpstanApi.method (backwards compatibility not guaranteed) + } if (($cond instanceof PropertyFetch || $cond instanceof NullsafePropertyFetch) && $this->inConfiguredClasses($cond->var) ) { diff --git a/tests/PHPStan/UniqueValuesRuleTest.php b/tests/PHPStan/UniqueValuesRuleTest.php index b7499e87..7edbe2ab 100644 --- a/tests/PHPStan/UniqueValuesRuleTest.php +++ b/tests/PHPStan/UniqueValuesRuleTest.php @@ -22,7 +22,7 @@ public function testRule(): void ], [ [ - 'Enum class BenSampo\Enum\Tests\PHPStan\Fixtures\DuplicateValue contains constants with duplicate values: [["A","B"]].', + 'Enum class BenSampo\Enum\Tests\PHPStan\Fixtures\DuplicateValue contains constants with duplicate values: ["A","B"].', 13, ], ],