diff --git a/.github/workflows/integrate.yaml b/.github/workflows/integrate.yaml index 620a5f93..ebd2abc7 100644 --- a/.github/workflows/integrate.yaml +++ b/.github/workflows/integrate.yaml @@ -6,7 +6,7 @@ on: branches: - master schedule: - - cron: "0 10 * * *" + - cron: "0 10 * * 6" jobs: static-code-analysis: @@ -18,8 +18,8 @@ jobs: fail-fast: false matrix: php-version: - - 8.0 - 8.1 + - 8.2 dependencies: - highest @@ -27,7 +27,7 @@ jobs: steps: - name: "Checkout" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: "Install PHP with extensions" uses: shivammathur/setup-php@v2 @@ -36,12 +36,12 @@ jobs: php-version: ${{ matrix.php-version }} - name: Install Composer dependencies - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v3 with: dependency-versions: ${{ matrix.dependencies }} - name: "Cache cache directory for vimeo/psalm" - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: .build/psalm key: php-${{ matrix.php-version }}-psalm-${{ github.sha }} @@ -64,26 +64,20 @@ jobs: fail-fast: false matrix: php-version: - - 8.0 - 8.1 - 8.2 symfony-version: - - 5 - 6 - 7 exclude: - - php-version: 8.0 - symfony-version: 6 - - php-version: 8.0 - symfony-version: 7 - php-version: 8.1 symfony-version: 7 steps: - name: "Checkout" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: "Install PHP with extensions" uses: shivammathur/setup-php@v2 @@ -96,7 +90,7 @@ jobs: run: composer config extra.symfony.require ${{ matrix.symfony-version }}.* - name: Install Composer dependencies - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v3 - name: "Run unit tests with phpunit" run: vendor/bin/phpunit --configuration=phpunit.xml diff --git a/README.md b/README.md index 7644c0f2..ccac6260 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ vendor/bin/psalm-plugin enable psalm/plugin-symfony | Symfony Psalm Plugin | PHP | Symfony | Psalm | |----------------------|------------|---------|-------| -| 5.x | ^7.4, ^8.0 | 5, 6 | 5 | +| 5.x | ^8.0 | 5, 6, 7 | 5 | | 4.x | ^7.4, ^8.0 | 4, 5, 6 | 4 | | 3.x | ^7.1, ^8.0 | 4, 5, 6 | 4 | | 2.x | ^7.1, ^8.0 | 4, 5 | 4 | diff --git a/composer.json b/composer.json index 6d3bc610..9b77764b 100644 --- a/composer.json +++ b/composer.json @@ -10,20 +10,20 @@ } ], "require": { - "php": "^7.4 || ^8.0", + "php": "^8.1", "ext-simplexml": "*", "symfony/framework-bundle": "^5.0 || ^6.0 || ^7.0", - "vimeo/psalm": "^5.1" + "vimeo/psalm": "^5.24" }, "require-dev": { - "symfony/form": "^5.0 || ^6.0 || ^7.0", "doctrine/annotations": "^1.8|^2", "doctrine/orm": "^2.9", "phpunit/phpunit": "~7.5 || ~9.5", "symfony/cache-contracts": "^1.0 || ^2.0", "symfony/console": "*", + "symfony/form": "^5.0 || ^6.0 || ^7.0", "symfony/messenger": "^5.0 || ^6.0 || ^7.0", - "symfony/security-guard": "*", + "symfony/security-core": "*", "symfony/serializer": "^5.0 || ^6.0 || ^7.0", "symfony/validator": "*", "twig/twig": "^2.10 || ^3.0", diff --git a/src/Handler/ConsoleHandler.php b/src/Handler/ConsoleHandler.php index c18f511f..def0894f 100644 --- a/src/Handler/ConsoleHandler.php +++ b/src/Handler/ConsoleHandler.php @@ -57,7 +57,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve break; case 'Symfony\Component\Console\Input\InputInterface::getargument': $identifier = self::getNodeIdentifier($args[0]->value); - if (!$identifier) { + if (null === $identifier) { break; } @@ -70,7 +70,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve break; case 'Symfony\Component\Console\Input\InputInterface::getoption': $identifier = self::getNodeIdentifier($args[0]->value); - if (!$identifier) { + if (null === $identifier) { break; } @@ -126,7 +126,7 @@ private static function analyseArgument(array $args, StatementsSource $statement $normalizedParams = self::normalizeArgumentParams($args); $identifier = self::getNodeIdentifier($normalizedParams['name']->value); - if (!$identifier) { + if (null === $identifier) { return; } @@ -170,7 +170,7 @@ private static function analyseOption(array $args, StatementsSource $statements_ $normalizedParams = self::normalizeOptionParams($args); $identifier = self::getNodeIdentifier($normalizedParams['name']->value); - if (!$identifier) { + if (null === $identifier) { return; } diff --git a/src/Handler/ContainerHandler.php b/src/Handler/ContainerHandler.php index c22ae57f..e750debc 100644 --- a/src/Handler/ContainerHandler.php +++ b/src/Handler/ContainerHandler.php @@ -35,10 +35,7 @@ class ContainerHandler implements AfterMethodCallAnalysisInterface, AfterClassLi 'Symfony\Bundle\FrameworkBundle\Test\TestContainer', ]; - /** - * @var ContainerMeta|null - */ - private static $containerMeta; + private static ?ContainerMeta $containerMeta = null; /** * @var array collection of cower-cased class names that are present in the container @@ -105,7 +102,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve if ('self' === $className) { $className = $event->getStatementsSource()->getSource()->getFQCLN(); } - if (!$idArgument->name instanceof Identifier || !$className) { + if (!$idArgument->name instanceof Identifier || null === $className) { return; } @@ -114,7 +111,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve } else { try { $serviceId = \constant($className.'::'.$idArgument->name->name); - } catch (\Exception $e) { + } catch (\Exception) { return; } } @@ -133,7 +130,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve } $class = $service->getClass(); - if ($class) { + if (null !== $class) { $codebase->classlikes->addFullyQualifiedClassName($class); $event->setReturnTypeCandidate(new Union([new TNamedObject($class)])); } @@ -141,7 +138,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve if (!$service->isPublic()) { /** @var class-string $kernelTestCaseClass */ $kernelTestCaseClass = 'Symfony\Bundle\FrameworkBundle\Test\KernelTestCase'; - $isTestContainer = $context->parent + $isTestContainer = null !== $context->parent && ($kernelTestCaseClass === $context->parent || is_subclass_of($context->parent, $kernelTestCaseClass) ); @@ -152,7 +149,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve ); } } - } catch (ServiceNotFoundException $e) { + } catch (ServiceNotFoundException) { IssueBuffer::accepts( new ServiceNotFound($serviceId, new CodeLocation($statements_source, $firstArg->value)), $statements_source->getSuppressedIssues() @@ -160,7 +157,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve } } - public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event) + public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event): void { $codebase = $event->getCodebase(); $statements_source = $event->getStatementsSource(); @@ -221,7 +218,7 @@ function ($c) use ($methodName) { private static function followsParameterNamingConvention(string $name): bool { - if (0 === strpos($name, 'env(')) { + if (str_starts_with($name, 'env(')) { return true; } diff --git a/src/Handler/HeaderBagHandler.php b/src/Handler/HeaderBagHandler.php index e5827089..401a17ad 100644 --- a/src/Handler/HeaderBagHandler.php +++ b/src/Handler/HeaderBagHandler.php @@ -6,7 +6,6 @@ use PhpParser\Node\Scalar\String_; use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface; -use Psalm\Type; use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TNull; @@ -24,7 +23,7 @@ public static function getClassLikeNames(): array ]; } - public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Type\Union + public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Union { $fq_classlike_name = $event->getFqClasslikeName(); $method_name_lowercase = $event->getMethodNameLowercase(); diff --git a/src/Plugin.php b/src/Plugin.php index ab61d402..ce9c5431 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -29,7 +29,7 @@ */ class Plugin implements PluginEntryPointInterface { - public function __invoke(RegistrationInterface $api, \SimpleXMLElement $config = null): void + public function __invoke(RegistrationInterface $registration, ?\SimpleXMLElement $config = null): void { require_once __DIR__.'/Handler/HeaderBagHandler.php'; require_once __DIR__.'/Handler/ContainerHandler.php'; @@ -39,13 +39,13 @@ public function __invoke(RegistrationInterface $api, \SimpleXMLElement $config = require_once __DIR__.'/Handler/DoctrineQueryBuilderHandler.php'; require_once __DIR__.'/Provider/FormGetErrorsReturnTypeProvider.php'; - $api->registerHooksFromClass(HeaderBagHandler::class); - $api->registerHooksFromClass(ConsoleHandler::class); - $api->registerHooksFromClass(ContainerDependencyHandler::class); - $api->registerHooksFromClass(RequiredSetterHandler::class); + $registration->registerHooksFromClass(HeaderBagHandler::class); + $registration->registerHooksFromClass(ConsoleHandler::class); + $registration->registerHooksFromClass(ContainerDependencyHandler::class); + $registration->registerHooksFromClass(RequiredSetterHandler::class); if (class_exists(\Doctrine\ORM\QueryBuilder::class)) { - $api->registerHooksFromClass(DoctrineQueryBuilderHandler::class); + $registration->registerHooksFromClass(DoctrineQueryBuilderHandler::class); } if (class_exists(AnnotationRegistry::class)) { @@ -54,10 +54,10 @@ public function __invoke(RegistrationInterface $api, \SimpleXMLElement $config = /** @psalm-suppress DeprecatedMethod */ AnnotationRegistry::registerLoader('class_exists'); } - $api->registerHooksFromClass(DoctrineRepositoryHandler::class); + $registration->registerHooksFromClass(DoctrineRepositoryHandler::class); require_once __DIR__.'/Handler/AnnotationHandler.php'; - $api->registerHooksFromClass(AnnotationHandler::class); + $registration->registerHooksFromClass(AnnotationHandler::class); } if (isset($config->containerXml)) { @@ -83,14 +83,14 @@ public function __invoke(RegistrationInterface $api, \SimpleXMLElement $config = require_once __DIR__.'/Handler/ParameterBagHandler.php'; ParameterBagHandler::init($containerMeta); - $api->registerHooksFromClass(ParameterBagHandler::class); + $registration->registerHooksFromClass(ParameterBagHandler::class); } - $api->registerHooksFromClass(ContainerHandler::class); + $registration->registerHooksFromClass(ContainerHandler::class); - $this->addStubs($api, __DIR__.'/Stubs/common'); - $this->addStubs($api, __DIR__.'/Stubs/'.Kernel::MAJOR_VERSION); - $this->addStubs($api, __DIR__.'/Stubs/php'); + $this->addStubs($registration, __DIR__.'/Stubs/common'); + $this->addStubs($registration, __DIR__.'/Stubs/'.Kernel::MAJOR_VERSION); + $this->addStubs($registration, __DIR__.'/Stubs/php'); if (isset($config->twigCachePath)) { $twig_cache_path = getcwd().DIRECTORY_SEPARATOR.ltrim((string) $config->twigCachePath, DIRECTORY_SEPARATOR); @@ -99,15 +99,15 @@ public function __invoke(RegistrationInterface $api, \SimpleXMLElement $config = } require_once __DIR__.'/Twig/CachedTemplatesTainter.php'; - $api->registerHooksFromClass(CachedTemplatesTainter::class); + $registration->registerHooksFromClass(CachedTemplatesTainter::class); require_once __DIR__.'/Twig/CachedTemplatesMapping.php'; - $api->registerHooksFromClass(CachedTemplatesMapping::class); + $registration->registerHooksFromClass(CachedTemplatesMapping::class); CachedTemplatesMapping::setCachePath($twig_cache_path); } require_once __DIR__.'/Twig/AnalyzedTemplatesTainter.php'; - $api->registerHooksFromClass(AnalyzedTemplatesTainter::class); + $registration->registerHooksFromClass(AnalyzedTemplatesTainter::class); if (isset($config->twigRootPath)) { $twig_root_path = trim((string) $config->twigRootPath, DIRECTORY_SEPARATOR); @@ -119,20 +119,20 @@ public function __invoke(RegistrationInterface $api, \SimpleXMLElement $config = TemplateFileAnalyzer::setTemplateRootPath($twig_root_path); } - $api->registerHooksFromClass(FormGetErrorsReturnTypeProvider::class); + $registration->registerHooksFromClass(FormGetErrorsReturnTypeProvider::class); } - private function addStubs(RegistrationInterface $api, string $path): void + private function addStubs(RegistrationInterface $registration, string $path): void { if (!is_dir($path)) { - // e.g. looking for stubs for version 3, but there aren't any at time of writing, so don't try and load them. + // e.g., looking for stubs for version 3, but there aren't any at time of writing, so don't try and load them. return; } $a = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); foreach ($a as $file) { if (!$file->isDir()) { - $api->addStubFile($file->getPathname()); + $registration->addStubFile($file->getPathname()); } } } diff --git a/src/Stubs/common/Component/PropertyAccess/PropertyAccessorInterface.stubphp b/src/Stubs/common/Component/PropertyAccess/PropertyAccessorInterface.stubphp index db8bd358..607809e5 100644 --- a/src/Stubs/common/Component/PropertyAccess/PropertyAccessorInterface.stubphp +++ b/src/Stubs/common/Component/PropertyAccess/PropertyAccessorInterface.stubphp @@ -11,7 +11,7 @@ interface PropertyAccessorInterface * @psalm-param mixed $value * @psalm-param-out T $objectOrArray */ - public function setValue(&$objectOrArray, $propertyPath, $value); + public function setValue(object|array &$objectOrArray, string|PropertyPathInterface $propertyPath, mixed $value); /** * @param object|array $objectOrArray @@ -19,7 +19,7 @@ interface PropertyAccessorInterface * * @return mixed */ - public function getValue($objectOrArray, $propertyPath); + public function getValue(object|array $objectOrArray, string|PropertyPathInterface $propertyPath): mixed; /** * @param object|array $objectOrArray @@ -27,7 +27,7 @@ interface PropertyAccessorInterface * * @return bool */ - public function isWritable($objectOrArray, $propertyPath); + public function isWritable(object|array $objectOrArray, string|PropertyPathInterface $propertyPath): bool; /** * @param object|array $objectOrArray @@ -35,5 +35,5 @@ interface PropertyAccessorInterface * * @return bool */ - public function isReadable($objectOrArray, $propertyPath); + public function isReadable(object|array $objectOrArray, string|PropertyPathInterface $propertyPath): bool; } diff --git a/src/Stubs/common/Component/Security/Core/Authorization/Voter/Voter.stubphp b/src/Stubs/common/Component/Security/Core/Authorization/Voter/Voter.stubphp deleted file mode 100644 index 57d88416..00000000 --- a/src/Stubs/common/Component/Security/Core/Authorization/Voter/Voter.stubphp +++ /dev/null @@ -1,42 +0,0 @@ - */ - private $classNames = []; + private array $classNames = []; /** * @var array */ - private $classLocators = []; + private array $classLocators = []; /** * @var array> */ - private $serviceLocators = []; + private array $serviceLocators = []; - /** - * @var ContainerBuilder - */ - private $container; + private ContainerBuilder $container; public function __construct(array $containerXmlPaths) { @@ -44,9 +41,9 @@ public function __construct(array $containerXmlPaths) /** * @throws ServiceNotFoundException */ - public function get(string $id, string $contextClass = null): Definition + public function get(string $id, ?string $contextClass = null): Definition { - if ($contextClass && isset($this->classLocators[$contextClass]) && isset($this->serviceLocators[$this->classLocators[$contextClass]]) && isset($this->serviceLocators[$this->classLocators[$contextClass]][$id])) { + if (null !== $contextClass && isset($this->classLocators[$contextClass]) && isset($this->serviceLocators[$this->classLocators[$contextClass]]) && isset($this->serviceLocators[$this->classLocators[$contextClass]][$id])) { $id = $this->serviceLocators[$this->classLocators[$contextClass]][$id]; try { @@ -67,10 +64,7 @@ public function get(string $id, string $contextClass = null): Definition return $definition; } - /** - * @return mixed|null - */ - public function getParameter(string $key) + public function getParameter(string $key): mixed { return $this->container->getParameter($key); } @@ -91,12 +85,12 @@ private function init(array $containerXmlPaths): void $containerXmlPath = null; foreach ($containerXmlPaths as $filePath) { $containerXmlPath = realpath((string) $filePath); - if ($containerXmlPath) { + if (false !== $containerXmlPath) { break; } } - if (!$containerXmlPath) { + if (!is_string($containerXmlPath)) { throw new ConfigException('Container xml file(s) not found!'); } @@ -111,14 +105,13 @@ private function init(array $containerXmlPaths): void $this->classLocators[$this->container->getDefinition($id)->getClass() ?? $id] = (string) $reference; } elseif ($definition->hasTag('container.service_locator')) { continue; - } elseif ($className = $definition->getClass()) { + } elseif (null !== $className = $definition->getClass()) { $this->classNames[] = $className; } } foreach ($this->container->findTaggedServiceIds('container.service_locator') as $key => $_) { - $definition = $this->container->getDefinition($key); - foreach ($definition->getArgument(0) as $id => $argument) { + foreach ($this->container->getDefinition($key)->getArgument(0) as $id => $argument) { if ($argument instanceof Reference) { $this->addServiceLocator($key, $id, $argument); } elseif ($argument instanceof ServiceClosureArgument) { @@ -139,10 +132,10 @@ private function addServiceLocator(string $key, string $id, Reference $reference try { $definition = $this->getDefinition((string) $reference); $className = $definition->getClass(); - if ($className) { + if (null !== $className) { $this->classNames[] = $className; } - } catch (ServiceNotFoundException $e) { + } catch (ServiceNotFoundException) { } } @@ -156,7 +149,7 @@ private function getDefinition(string $id): Definition } catch (ServiceNotFoundException $serviceNotFoundException) { try { $alias = $this->container->getAlias($id); - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { throw $serviceNotFoundException; } diff --git a/src/Twig/TemplateFileAnalyzer.php b/src/Twig/TemplateFileAnalyzer.php index cbb3251f..76b968c4 100644 --- a/src/Twig/TemplateFileAnalyzer.php +++ b/src/Twig/TemplateFileAnalyzer.php @@ -18,15 +18,12 @@ */ class TemplateFileAnalyzer extends FileAnalyzer { - /** - * @var string - */ - private static $rootPath = 'templates'; + private static string $rootPath = 'templates'; /** * @var list */ - private static $extensionClasses = []; + private static array $extensionClasses = []; /** * @param list $extensionClasses @@ -37,8 +34,8 @@ public static function initExtensions(array $extensionClasses): void } public function analyze( - PsalmContext $file_context = null, - PsalmContext $global_context = null + ?PsalmContext $file_context = null, + ?PsalmContext $global_context = null ): void { $codebase = $this->project_analyzer->getCodebase(); $taint = $codebase->taint_flow_graph; diff --git a/tests/acceptance/acceptance/ContainerService.feature b/tests/acceptance/acceptance/ContainerService.feature index eca77100..03e58f52 100644 --- a/tests/acceptance/acceptance/ContainerService.feature +++ b/tests/acceptance/acceptance/ContainerService.feature @@ -4,23 +4,26 @@ Feature: Container service Background: Given I have Symfony plugin enabled - - Scenario: Asserting psalm recognizes return type of service got via 'ContainerInterface::get()' - Given I have the following code + And I have the following code preamble """ container->get(SomeService::class)->do(); + $container->get(SomeService::class)->do(); } } """ @@ -30,19 +33,11 @@ Feature: Container service Scenario: Asserting psalm recognizes return type of service got via 'ContainerInterface::get()'. Given I have the following code """ - container->get(SomeService::class)->nosuchmethod(); + $container->get(SomeService::class)->nosuchmethod(); } } """ @@ -55,18 +50,16 @@ Feature: Container service Scenario: Container get(self::class) should not crash Given I have the following code """ - container->get(self::class)->index(); + $container->get(self::class)->index(); } } """ When I run Psalm Then I see these errors - | Type | Message | - | MissingReturnType | Method SomeController::index does not have a return type, expecting void | + | Type | Message | + | MixedMethodCall | Cannot determine the type of the object on the left hand side of this expression | + And I see no other errors diff --git a/tests/acceptance/acceptance/ContainerXml.feature b/tests/acceptance/acceptance/ContainerXml.feature index 8c4f8ab7..8021a8e1 100644 --- a/tests/acceptance/acceptance/ContainerXml.feature +++ b/tests/acceptance/acceptance/ContainerXml.feature @@ -7,19 +7,22 @@ Feature: Container XML config """ ../../tests/acceptance/container.xml """ + And I have the following code preamble + """ + container->get('service_container')->has('lorem'); + return $container->get('service_container')->has('lorem'); } } """ @@ -29,15 +32,11 @@ Feature: Container XML config Scenario: Psalm emits when service ID not found in container' Given I have the following code """ - container->get('not_a_service')->has('lorem'); + $container->get('not_a_service')->has('lorem'); } } """ @@ -49,18 +48,12 @@ Feature: Container XML config Scenario: Using service both via alias and class const Given I have the following code """ - container->get('http_kernel'); - $this->container->get(HttpKernelInterface::class); + $container->get('http_kernel'); + $container->get(HttpKernelInterface::class); } } """ @@ -70,15 +63,11 @@ Feature: Container XML config Scenario: Using private service Given I have the following code """ - container->get('private_service'); + $container->get('private_service'); } } """ diff --git a/tests/acceptance/acceptance/HeaderBag.feature b/tests/acceptance/acceptance/HeaderBag.feature index 157278c0..ae1a753c 100644 --- a/tests/acceptance/acceptance/HeaderBag.feature +++ b/tests/acceptance/acceptance/HeaderBag.feature @@ -2,7 +2,7 @@ Feature: Header get Background: - Given I have issue handler "UnusedFunctionCall" suppressed + Given I have issue handler "UnusedVariable" suppressed And I have Symfony plugin enabled And I have the following code preamble """ @@ -11,24 +11,23 @@ Feature: Header get use Symfony\Component\HttpFoundation\Request; """ - Scenario: HeaderBag get method return type should return `?string` (unless third argument is provided for < Sf4.4) + Scenario: HeaderBag get method return type should return `?string` Given I have the following code """ class App { public function index(Request $request): void { - $string = $request->headers->get('nullable_string'); - if (!$string) { - return; - } - - trim($string); + /** @psalm-trace $nullableString */ + $nullableString = $request->headers->get('nullable_string'); } } """ When I run Psalm - Then I see no errors + Then I see these errors + | Type | Message | + | Trace | $nullableString: null\|string | + And I see no other errors Scenario: HeaderBag get method return type should return `string` if default value is provided with string Given I have the following code @@ -37,11 +36,13 @@ Feature: Header get { public function index(Request $request): void { + /** @psalm-trace $string */ $string = $request->headers->get('string', 'string'); - - trim($string); } } """ When I run Psalm - Then I see no errors + Then I see these errors + | Type | Message | + | Trace | $string: string | + And I see no other errors diff --git a/tests/acceptance/acceptance/NamingConventions.feature b/tests/acceptance/acceptance/NamingConventions.feature index a376170f..928149fa 100644 --- a/tests/acceptance/acceptance/NamingConventions.feature +++ b/tests/acceptance/acceptance/NamingConventions.feature @@ -7,19 +7,22 @@ Feature: Naming conventions """ ../../tests/acceptance/container.xml """ + And I have the following code preamble + """ + container->get('service_container')->has('lorem'); + return $container->get('service_container')->has('lorem'); } } """ @@ -29,15 +32,11 @@ Feature: Naming conventions Scenario: Detects service naming convention violation Given I have the following code """ - container->get('wronglyNamedService'); + $container->get('wronglyNamedService'); } } """ @@ -50,17 +49,11 @@ Feature: Naming conventions Scenario: No service naming convention violation when using FQCNs Given I have the following code """ - container->get(HttpKernelInterface::class); + $container->get(HttpKernelInterface::class); } } """ @@ -70,15 +63,11 @@ Feature: Naming conventions Scenario: No naming convention violation for parameter Given I have the following code """ - container->getParameter('kernel.cache_dir'); + $container->getParameter('kernel.cache_dir'); } } """ @@ -88,15 +77,11 @@ Feature: Naming conventions Scenario: Detects parameter naming convention violation Given I have the following code """ - container->getParameter('wronglyNamedParameter'); + $container->getParameter('wronglyNamedParameter'); } } """ @@ -109,15 +94,11 @@ Feature: Naming conventions Scenario: No parameter naming convention violation when using environment variables Given I have the following code """ - container->getParameter('env(SOME_ENV_VAR)'); + $container->getParameter('env(SOME_ENV_VAR)'); } } """ diff --git a/tests/acceptance/acceptance/PropertyAccessorInterface.feature b/tests/acceptance/acceptance/PropertyAccessorInterface.feature index 79499b96..8503fe62 100644 --- a/tests/acceptance/acceptance/PropertyAccessorInterface.feature +++ b/tests/acceptance/acceptance/PropertyAccessorInterface.feature @@ -9,6 +9,7 @@ Feature: PropertyAccessorInterface setValue($company, 'name', 'Acme v2'); - array_key_exists('name', $company); + /** @psalm-trace $company */ """ When I run Psalm - Then I see no errors + Then I see these errors + | Type | Message | + | Trace | $company: array | + And I see no other errors Scenario: Set value keeps object instance if an object is passed Given I have the following code @@ -36,28 +40,26 @@ Feature: PropertyAccessorInterface $propertyAccessor->setValue($company, 'name', 'Acme v2'); - echo $company->name; + /** @psalm-trace $company */ """ When I run Psalm - Then I see no errors + Then I see these errors + | Type | Message | + | Trace | $company: Company | + And I see no other errors Scenario: Set value does not modify the propertyAccessor variable Given I have the following code """ - use Symfony\Component\PropertyAccess\PropertyAccessorInterface; - class Company { - /** - * @var PropertyAccessorInterface - */ - private $propertyAccessor; - - public function __construct(PropertyAccessorInterface $propertyAccessor) { - $this->propertyAccessor = $propertyAccessor; + public function __construct( + private PropertyAccessorInterface $propertyAccessor, + ) { } - public function doThings(Company $thing): void { + public function doThings(Company $thing): void + { $this->propertyAccessor->setValue($thing, 'foo', 'bar'); $this->propertyAccessor->setValue($thing, 'foo', 'bar'); } diff --git a/tests/acceptance/acceptance/Voter.feature b/tests/acceptance/acceptance/Voter.feature deleted file mode 100644 index 2dca842d..00000000 --- a/tests/acceptance/acceptance/Voter.feature +++ /dev/null @@ -1,40 +0,0 @@ -@symfony-common -Feature: Voter abstract class - - Background: - Given I have Symfony plugin enabled - And I have the following code preamble - """ -