diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 093f4bb1da..b8508809ae 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.4.0 ----- + * Added `lint:container` to check that services wiring matches type declarations * Added `MailerAssertionsTrait` * Deprecated support for `templating` engine in `TemplateController`, use Twig instead * Deprecated the `$parser` argument of `ControllerResolver::__construct()` and `DelegatingLoader::__construct()` diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php index c7c6cb4507..04ecff767f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php @@ -11,19 +11,21 @@ namespace Symfony\Bundle\FrameworkBundle\Command; +use Symfony\Component\Config\ConfigCache; +use Symfony\Component\Config\FileLocator; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Config\ConfigCache; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CheckTypeHintsPass; +use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass; use Symfony\Component\DependencyInjection\Compiler\PassConfig; -use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -class ContainerLintCommand extends Command +final class ContainerLintCommand extends Command { + protected static $defaultName = 'lint:container'; + /** * @var ContainerBuilder */ @@ -35,37 +37,33 @@ class ContainerLintCommand extends Command protected function configure() { $this - ->setDescription('Lints container for services arguments type hints') - ->setHelp('This command will parse all your defined services and check that you are injecting service without type error based on type hints.') - ->addOption('only-used-services', 'o', InputOption::VALUE_NONE, 'Check only services that are used in your application') + ->setDescription('Ensures that arguments injected into services match type declarations') + ->setHelp('This command parses service definitions and ensures that injected values match the type declarations of each services\' class.') + ->addOption('ignore-unused-services', 'o', InputOption::VALUE_NONE, 'Ignore unused services') ; } /** * {@inheritdoc} */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $container = $this->getContainerBuilder(); $container->setParameter('container.build_id', 'lint_container'); $container->addCompilerPass( - new CheckTypeHintsPass(), - $input->getOption('only-used-services') ? PassConfig::TYPE_AFTER_REMOVING : PassConfig::TYPE_BEFORE_OPTIMIZATION + new CheckTypeDeclarationsPass(true), + $input->getOption('ignore-unused-services') ? PassConfig::TYPE_AFTER_REMOVING : PassConfig::TYPE_OPTIMIZE, + -5 ); $container->compile(); + + return 0; } - /** - * Loads the ContainerBuilder from the cache. - * - * @return ContainerBuilder - * - * @throws \LogicException - */ - protected function getContainerBuilder() + private function getContainerBuilder(): ContainerBuilder { if ($this->containerBuilder) { return $this->containerBuilder; @@ -74,10 +72,9 @@ class ContainerLintCommand extends Command $kernel = $this->getApplication()->getKernel(); if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) { - $buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, get_class($kernel)); + $buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel)); $container = $buildContainer(); - $container->getCompilerPassConfig()->setRemovingPasses(array()); - $container->compile(); + $container->getCompilerPassConfig()->setRemovingPasses([]); } else { (new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump')); } diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 7da5b6b534..d1771da846 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.4.0 ----- - * added `CheckTypeHintsPass` to check injected parameters type during compilation + * added `CheckTypeDeclarationsPass` to check injected parameters type during compilation * added support for opcache.preload by generating a preloading script in the cache folder * added support for dumping the container in one file instead of many files * deprecated support for short factories and short configurators in Yaml diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php new file mode 100644 index 0000000000..0dfd9ae6f6 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException; +use Symfony\Component\DependencyInjection\Parameter; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; + +/** + * Checks whether injected parameters are compatible with type declarations. + * + * This pass should be run after all optimization passes. + * + * It can be added either: + * * before removing passes to check all services even if they are not currently used, + * * after removing passes to check only services are used in the app. + * + * @author Nicolas Grekas + * @author Julien Maulny + */ +final class CheckTypeDeclarationsPass extends AbstractRecursivePass +{ + private const SCALAR_TYPES = ['int', 'float', 'bool', 'string']; + + private $autoload; + + /** + * @param bool $autoload Whether services who's class in not loaded should be checked or not. + * Defaults to false to save loading code during compilation. + */ + public function __construct(bool $autoload = false) + { + $this->autoload = $autoload; + } + + /** + * {@inheritdoc} + */ + protected function processValue($value, $isRoot = false) + { + if (!$value instanceof Definition) { + return parent::processValue($value, $isRoot); + } + + if (!$this->autoload && !class_exists($class = $value->getClass(), false) && !interface_exists($class, false)) { + return parent::processValue($value, $isRoot); + } + + if (ServiceLocator::class === $value->getClass()) { + return parent::processValue($value, $isRoot); + } + + if ($constructor = $this->getConstructor($value, false)) { + $this->checkTypeDeclarations($value, $constructor, $value->getArguments()); + } + + foreach ($value->getMethodCalls() as $methodCall) { + $reflectionMethod = $this->getReflectionMethod($value, $methodCall[0]); + + $this->checkTypeDeclarations($value, $reflectionMethod, $methodCall[1]); + } + + return parent::processValue($value, $isRoot); + } + + /** + * @throws InvalidArgumentException When not enough parameters are defined for the method + */ + private function checkTypeDeclarations(Definition $checkedDefinition, \ReflectionFunctionAbstract $reflectionFunction, array $configurationArguments): void + { + $numberOfRequiredParameters = $reflectionFunction->getNumberOfRequiredParameters(); + + if (\count($configurationArguments) < $numberOfRequiredParameters) { + throw new InvalidArgumentException(sprintf('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed.', $this->currentId, $reflectionFunction->class, $reflectionFunction->name, $numberOfRequiredParameters, \count($configurationArguments))); + } + + $reflectionParameters = $reflectionFunction->getParameters(); + $checksCount = min($reflectionFunction->getNumberOfParameters(), \count($configurationArguments)); + + for ($i = 0; $i < $checksCount; ++$i) { + if (!$reflectionParameters[$i]->hasType() || $reflectionParameters[$i]->isVariadic()) { + continue; + } + + $this->checkType($checkedDefinition, $configurationArguments[$i], $reflectionParameters[$i]); + } + + if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) { + $variadicParameters = \array_slice($configurationArguments, $lastParameter->getPosition()); + + foreach ($variadicParameters as $variadicParameter) { + $this->checkType($checkedDefinition, $variadicParameter, $lastParameter); + } + } + } + + /** + * @throws InvalidParameterTypeException When a parameter is not compatible with the declared type + */ + private function checkType(Definition $checkedDefinition, $configurationArgument, \ReflectionParameter $parameter): void + { + $parameterTypeName = $parameter->getType()->getName(); + + $referencedDefinition = $configurationArgument; + + if ($referencedDefinition instanceof Reference) { + if (!$this->container->has($referencedDefinition)) { + return; + } + + $referencedDefinition = $this->container->findDefinition((string) $referencedDefinition); + } + + if ('self' === $parameterTypeName) { + $parameterTypeName = $parameter->getDeclaringClass()->getName(); + } + if ('static' === $parameterTypeName) { + $parameterTypeName = $checkedDefinition->getClass(); + } + + if ($referencedDefinition instanceof Definition) { + $class = $referencedDefinition->getClass(); + + if (!$class || (!$this->autoload && !class_exists($class, false) && !interface_exists($class, false))) { + return; + } + + if (!is_a($class, $parameterTypeName, true)) { + throw new InvalidParameterTypeException($this->currentId, $class, $parameter); + } + } else { + if (null === $configurationArgument && $parameter->allowsNull()) { + return; + } + + if (\in_array($parameterTypeName, self::SCALAR_TYPES, true) && is_scalar($configurationArgument)) { + return; + } + + if ('iterable' === $parameterTypeName && $configurationArgument instanceof IteratorArgument) { + return; + } + + if ('Traversable' === $parameterTypeName && $configurationArgument instanceof IteratorArgument) { + return; + } + + if ($configurationArgument instanceof Parameter) { + return; + } + + $checkFunction = sprintf('is_%s', $parameter->getType()->getName()); + + if (!$parameter->getType()->isBuiltin() || !$checkFunction($configurationArgument)) { + throw new InvalidParameterTypeException($this->currentId, \gettype($configurationArgument), $parameter); + } + } + } +} diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeHintsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeHintsPass.php deleted file mode 100644 index 41085b8e68..0000000000 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeHintsPass.php +++ /dev/null @@ -1,184 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Compiler; - -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; -use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeHintException; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; - -/** - * Checks whether injected parameters types are compatible with type hints. - * This pass should be run after all optimization passes. - * So it can be added either: - * * before removing (PassConfig::TYPE_BEFORE_REMOVING) so that it will check - * all services, even if they are not currently used, - * * after removing (PassConfig::TYPE_AFTER_REMOVING) so that it will check - * only services you are using. - * - * @author Nicolas Grekas - * @author Julien Maulny - */ -class CheckTypeHintsPass extends AbstractRecursivePass -{ - /** - * If set to true, allows to autoload classes during compilation - * in order to check type hints on parameters that are not yet loaded. - * Defaults to false to prevent code loading during compilation. - * - * @param bool - */ - private $autoload; - - public function __construct(bool $autoload = false) - { - $this->autoload = $autoload; - } - - /** - * {@inheritdoc} - */ - protected function processValue($value, $isRoot = false) - { - if (!$value instanceof Definition) { - return parent::processValue($value, $isRoot); - } - - if (!$this->autoload && !class_exists($className = $this->getClassName($value), false) && !interface_exists($className, false)) { - return parent::processValue($value, $isRoot); - } - - if (ServiceLocator::class === $value->getClass()) { - return parent::processValue($value, $isRoot); - } - - if (null !== $constructor = $this->getConstructor($value, false)) { - $this->checkArgumentsTypeHints($constructor, $value->getArguments()); - } - - foreach ($value->getMethodCalls() as $methodCall) { - $reflectionMethod = $this->getReflectionMethod($value, $methodCall[0]); - - $this->checkArgumentsTypeHints($reflectionMethod, $methodCall[1]); - } - - return parent::processValue($value, $isRoot); - } - - /** - * Check type hints for every parameter of a method/constructor. - * - * @throws InvalidArgumentException on type hint incompatibility - */ - private function checkArgumentsTypeHints(\ReflectionFunctionAbstract $reflectionFunction, array $configurationArguments): void - { - $numberOfRequiredParameters = $reflectionFunction->getNumberOfRequiredParameters(); - - if (count($configurationArguments) < $numberOfRequiredParameters) { - throw new InvalidArgumentException(sprintf( - 'Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed.', $this->currentId, $reflectionFunction->class, $reflectionFunction->name, $numberOfRequiredParameters, count($configurationArguments))); - } - - $reflectionParameters = $reflectionFunction->getParameters(); - $checksCount = min($reflectionFunction->getNumberOfParameters(), count($configurationArguments)); - - for ($i = 0; $i < $checksCount; ++$i) { - if (!$reflectionParameters[$i]->hasType() || $reflectionParameters[$i]->isVariadic()) { - continue; - } - - $this->checkTypeHint($configurationArguments[$i], $reflectionParameters[$i]); - } - - if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) { - $variadicParameters = array_slice($configurationArguments, $lastParameter->getPosition()); - - foreach ($variadicParameters as $variadicParameter) { - $this->checkTypeHint($variadicParameter, $lastParameter); - } - } - } - - /** - * Check type hints compatibility between - * a definition argument and a reflection parameter. - * - * @throws InvalidArgumentException on type hint incompatibility - */ - private function checkTypeHint($configurationArgument, \ReflectionParameter $parameter): void - { - $referencedDefinition = $configurationArgument; - - if ($referencedDefinition instanceof Reference) { - $referencedDefinition = $this->container->findDefinition((string) $referencedDefinition); - } - - if ($referencedDefinition instanceof Definition) { - $class = $this->getClassName($referencedDefinition); - - if (!$this->autoload && !class_exists($class, false)) { - return; - } - - if (!is_a($class, $parameter->getType()->getName(), true)) { - throw new InvalidParameterTypeHintException($this->currentId, null === $class ? 'null' : $class, $parameter); - } - } else { - if (null === $configurationArgument && $parameter->allowsNull()) { - return; - } - - if ($parameter->getType()->isBuiltin() && is_scalar($configurationArgument)) { - return; - } - - if ('iterable' === $parameter->getType()->getName() && $configurationArgument instanceof IteratorArgument) { - return; - } - - if ('Traversable' === $parameter->getType()->getName() && $configurationArgument instanceof IteratorArgument) { - return; - } - - $checkFunction = 'is_'.$parameter->getType()->getName(); - - if (!$parameter->getType()->isBuiltin() || !$checkFunction($configurationArgument)) { - throw new InvalidParameterTypeHintException($this->currentId, gettype($configurationArgument), $parameter); - } - } - } - - /** - * Get class name from value that can have a factory. - * - * @return string|null - */ - private function getClassName($value) - { - if (is_array($factory = $value->getFactory())) { - list($class, $method) = $factory; - if ($class instanceof Reference) { - $class = $this->container->findDefinition((string) $class)->getClass(); - } elseif (null === $class) { - $class = $value->getClass(); - } elseif ($class instanceof Definition) { - $class = $this->getClassName($class); - } - } else { - $class = $value->getClass(); - } - - return $class; - } -} diff --git a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php new file mode 100644 index 0000000000..206561fa95 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Exception; + +/** + * Thrown when trying to inject a parameter into a constructor/method with an incompatible type. + * + * @author Nicolas Grekas + * @author Julien Maulny + */ +class InvalidParameterTypeException extends InvalidArgumentException +{ + public function __construct(string $serviceId, string $type, \ReflectionParameter $parameter) + { + parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $parameter->getType()->getName(), $type)); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeHintException.php b/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeHintException.php deleted file mode 100644 index a04d071972..0000000000 --- a/src/Symfony/Component/DependencyInjection/Exception/InvalidParameterTypeHintException.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Exception; - -/** - * Thrown when trying to inject a parameter into a constructor/method - * with a type that does not match type hint. - * - * @author Nicolas Grekas - * @author Julien Maulny - */ -class InvalidParameterTypeHintException extends InvalidArgumentException -{ - public function __construct(string $serviceId, string $typeHint, \ReflectionParameter $parameter) - { - parent::__construct(sprintf( - 'Invalid definition for service "%s": argument %d of "%s::%s" requires a "%s", "%s" passed.', $serviceId, $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $parameter->getType()->getName(), $typeHint)); - } -} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeHintsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php similarity index 50% rename from src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeHintsPassTest.php rename to src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php index 690c628cb6..51bc7c6779 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeHintsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -12,77 +12,73 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\CheckTypeHintsPass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Bar; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarOptionalArgument; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarOptionalArgumentNotNull; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo; +use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Bar; +use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarMethodCall; +use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarOptionalArgument; +use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarOptionalArgumentNotNull; +use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo; /** * @author Nicolas Grekas * @author Julien Maulny */ -class CheckTypeHintsPassTest extends TestCase +class CheckTypeDeclarationsPassTest extends TestCase { - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Bar::__construct" requires a "stdClass", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo" passed - */ - public function testProcessThrowsExceptionOnInvalidTypeHintsConstructorArguments() + public function testProcessThrowsExceptionOnInvalidTypesConstructorArguments() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Bar::__construct" accepts "stdClass", "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo" passed.'); + $container = new ContainerBuilder(); $container->register('foo', Foo::class); $container->register('bar', Bar::class) ->addArgument(new Reference('foo')); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setFoo" requires a "stdClass", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo" passed - */ - public function testProcessThrowsExceptionOnInvalidTypeHintsMethodCallArguments() + public function testProcessThrowsExceptionOnInvalidTypesMethodCallArguments() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setFoo" accepts "stdClass", "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo" passed.'); + $container = new ContainerBuilder(); $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoo', array(new Reference('foo'))); + ->addMethodCall('setFoo', [new Reference('foo')]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Bar::__construct" requires a "stdClass", "NULL" passed - */ public function testProcessFailsWhenPassingNullToRequiredArgument() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Bar::__construct" accepts "stdClass", "NULL" passed.'); + $container = new ContainerBuilder(); $container->register('bar', Bar::class) ->addArgument(null); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Bar::__construct()" requires 1 arguments, 0 passed - */ public function testProcessThrowsExceptionWhenMissingArgumentsInConstructor() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Bar::__construct()" requires 1 arguments, 0 passed.'); + $container = new ContainerBuilder(); $container->register('bar', Bar::class); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } public function testProcessSuccessWhenPassingTooManyArgumentInConstructor() @@ -94,7 +90,7 @@ class CheckTypeHintsPassTest extends TestCase ->addArgument(new Reference('foo')) ->addArgument(new Reference('foo')); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->addToAssertionCount(1); } @@ -105,62 +101,59 @@ class CheckTypeHintsPassTest extends TestCase $container->register(Foo::class, Foo::class); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(Foo::class, $container->get(Foo::class)); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setFoo()" requires 1 arguments, 0 passed - */ public function testProcessThrowsExceptionWhenMissingArgumentsInMethodCall() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setFoo()" requires 1 arguments, 0 passed.'); + $container = new ContainerBuilder(); $container->register('foo', \stdClass::class); $container->register('bar', BarMethodCall::class) ->addArgument(new Reference('foo')) - ->addMethodCall('setFoo', array()); + ->addMethodCall('setFoo', []); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setFoosVariadic" requires a "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo", "stdClass" passed - */ public function testProcessVariadicFails() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 2 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setFoosVariadic" accepts "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo", "stdClass" passed.'); + $container = new ContainerBuilder(); $container->register('stdClass', \stdClass::class); $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoosVariadic', array( + ->addMethodCall('setFoosVariadic', [ new Reference('foo'), new Reference('foo'), new Reference('stdClass'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setFoosVariadic" requires a "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo", "stdClass" passed - */ public function testProcessVariadicFailsOnPassingBadTypeOnAnotherArgument() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setFoosVariadic" accepts "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo", "stdClass" passed.'); + $container = new ContainerBuilder(); $container->register('stdClass', \stdClass::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoosVariadic', array( + ->addMethodCall('setFoosVariadic', [ new Reference('stdClass'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } public function testProcessVariadicSuccess() @@ -169,13 +162,13 @@ class CheckTypeHintsPassTest extends TestCase $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoosVariadic', array( + ->addMethodCall('setFoosVariadic', [ new Reference('foo'), new Reference('foo'), new Reference('foo'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(Foo::class, $container->get('bar')->foo); } @@ -186,11 +179,11 @@ class CheckTypeHintsPassTest extends TestCase $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoosOptional', array( + ->addMethodCall('setFoosOptional', [ new Reference('foo'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(Foo::class, $container->get('bar')->foo); } @@ -201,33 +194,32 @@ class CheckTypeHintsPassTest extends TestCase $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoosOptional', array( + ->addMethodCall('setFoosOptional', [ new Reference('foo'), new Reference('foo'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(Foo::class, $container->get('bar')->foo); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setFoosOptional" requires a "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo", "stdClass" passed - */ public function testProcessFailsWhenUsingOptionalArgumentWithBadType() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 2 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setFoosOptional" accepts "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo", "stdClass" passed.'); + $container = new ContainerBuilder(); $container->register('stdClass', \stdClass::class); $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoosOptional', array( + ->addMethodCall('setFoosOptional', [ new Reference('foo'), new Reference('stdClass'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } public function testProcessSuccessWhenPassingNullToOptional() @@ -237,37 +229,35 @@ class CheckTypeHintsPassTest extends TestCase $container->register('bar', BarOptionalArgument::class) ->addArgument(null); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertNull($container->get('bar')->foo); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarOptionalArgumentNotNull::__construct" requires a "int", "NULL" passed - */ public function testProcessSuccessWhenPassingNullToOptionalThatDoesNotAcceptNull() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarOptionalArgumentNotNull::__construct" accepts "int", "NULL" passed.'); + $container = new ContainerBuilder(); $container->register('bar', BarOptionalArgumentNotNull::class) ->addArgument(null); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarOptionalArgument::__construct" requires a "stdClass", "string" passed - */ public function testProcessFailsWhenPassingBadTypeToOptional() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarOptionalArgument::__construct" accepts "stdClass", "string" passed.'); + $container = new ContainerBuilder(); $container->register('bar', BarOptionalArgument::class) ->addArgument('string instead of stdClass'); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertNull($container->get('bar')->foo); } @@ -277,97 +267,88 @@ class CheckTypeHintsPassTest extends TestCase $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setScalars', array( + ->addMethodCall('setScalars', [ 1, 'string', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(BarMethodCall::class, $container->get('bar')); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Bar::__construct" requires a "stdClass", "integer" passed - */ - public function testProcessFailsOnPassingScalarTypeToConstructorTypeHintedWithClass() + public function testProcessFailsOnPassingScalarTypeToConstructorTypedWithClass() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Bar::__construct" accepts "stdClass", "integer" passed.'); + $container = new ContainerBuilder(); $container->register('bar', Bar::class) ->addArgument(1); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setFoo" requires a "stdClass", "string" passed - */ - public function testProcessFailsOnPassingScalarTypeToMethodTypeHintedWithClass() + public function testProcessFailsOnPassingScalarTypeToMethodTypedWithClass() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setFoo" accepts "stdClass", "string" passed.'); + $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setFoo', array( + ->addMethodCall('setFoo', [ 'builtin type instead of class', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\BarMethodCall::setScalars" requires a "int", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo" passed - */ - public function testProcessFailsOnPassingClassToScalarTypeHintedParameter() + public function testProcessFailsOnPassingClassToScalarTypedParameter() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setScalars" accepts "int", "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo" passed.'); + $container = new ContainerBuilder(); $container->register('foo', Foo::class); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setScalars', array( + ->addMethodCall('setScalars', [ new Reference('foo'), new Reference('foo'), - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * Strict mode not yet handled. - */ public function testProcessSuccessOnPassingBadScalarType() { $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setScalars', array( + ->addMethodCall('setScalars', [ 1, true, - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(BarMethodCall::class, $container->get('bar')); } - /** - * Strict mode not yet handled. - */ public function testProcessSuccessPassingBadScalarTypeOptionalArgument() { $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setScalars', array( + ->addMethodCall('setScalars', [ 1, 'string', 'string instead of optional boolean', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(BarMethodCall::class, $container->get('bar')); } @@ -377,27 +358,24 @@ class CheckTypeHintsPassTest extends TestCase $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setArray', array( - array(), - )); + ->addMethodCall('setArray', [[]]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(BarMethodCall::class, $container->get('bar')); } - public function testProcessSuccessWhenPassingIntegerToArrayTypeHintedParameter() + public function testProcessSuccessWhenPassingIntegerToArrayTypedParameter() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarMethodCall::setArray" accepts "array", "integer" passed.'); + $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setArray', array( - 1, - )); + ->addMethodCall('setArray', [1]); - (new CheckTypeHintsPass(true))->process($container); - - $this->addToAssertionCount(1); + (new CheckTypeDeclarationsPass(true))->process($container); } public function testProcessSuccessWhenPassingAnIteratorArgumentToIterable() @@ -405,11 +383,9 @@ class CheckTypeHintsPassTest extends TestCase $container = new ContainerBuilder(); $container->register('bar', BarMethodCall::class) - ->addMethodCall('setIterable', array( - new IteratorArgument(array()), - )); + ->addMethodCall('setIterable', [new IteratorArgument([])]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->addToAssertionCount(1); } @@ -420,57 +396,43 @@ class CheckTypeHintsPassTest extends TestCase $container->register('foo', Foo::class); $container->register('bar', Bar::class) - ->setFactory(array( + ->setFactory([ new Reference('foo'), 'createBar', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + /* Asserts that the class of Bar is well detected */ + $container->register('bar_call', BarMethodCall::class) + ->addMethodCall('setBar', [new Reference('bar')]); + + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(Bar::class, $container->get('bar')); } - public function testProcessFactoryWhithClassName() - { - $container = new ContainerBuilder(); - - $container->register(Foo::class, Foo::class); - $container->register(Bar::class, Bar::class) - ->setFactory(array( - new Reference(Foo::class), - 'createBar', - )); - - (new CheckTypeHintsPass(true))->process($container); - - $this->assertInstanceOf(Bar::class, $container->get(Bar::class)); - } - - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 0 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo::createBarArguments" requires a "stdClass", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo" passed - */ public function testProcessFactoryFailsOnInvalidParameterType() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo::createBarArguments" accepts "stdClass", "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo" passed.'); + $container = new ContainerBuilder(); $container->register('foo', Foo::class); $container->register('bar', Bar::class) ->addArgument(new Reference('foo')) - ->setFactory(array( + ->setFactory([ new Reference('foo'), 'createBarArguments', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Invalid definition for service "bar": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo::createBarArguments" requires a "stdClass", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeHintsPass\Foo" passed - */ public function testProcessFactoryFailsOnInvalidParameterTypeOptional() { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar": argument 2 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo::createBarArguments" accepts "stdClass", "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\Foo" passed.'); + $container = new ContainerBuilder(); $container->register('stdClass', \stdClass::class); @@ -478,12 +440,12 @@ class CheckTypeHintsPassTest extends TestCase $container->register('bar', Bar::class) ->addArgument(new Reference('stdClass')) ->addArgument(new Reference('foo')) - ->setFactory(array( + ->setFactory([ new Reference('foo'), 'createBarArguments', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); } public function testProcessFactorySuccessOnValidTypes() @@ -495,12 +457,12 @@ class CheckTypeHintsPassTest extends TestCase $container->register('bar', Bar::class) ->addArgument(new Reference('stdClass')) ->addArgument(new Reference('stdClass')) - ->setFactory(array( + ->setFactory([ new Reference('foo'), 'createBarArguments', - )); + ]); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->addToAssertionCount(1); } @@ -512,7 +474,7 @@ class CheckTypeHintsPassTest extends TestCase $container->register('bar', \DateTime::class) ->setFactory('date_create'); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(\DateTime::class, $container->get('bar')); } @@ -524,13 +486,13 @@ class CheckTypeHintsPassTest extends TestCase $container->register('foo', FooNotExisting::class); $container->register('bar', BarNotExisting::class) ->addArgument(new Reference('foo')) - ->addMethodCall('setFoo', array( + ->addMethodCall('setFoo', [ new Reference('foo'), 'string', 1, - )); + ]); - (new CheckTypeHintsPass())->process($container); + (new CheckTypeDeclarationsPass())->process($container); $this->addToAssertionCount(1); } @@ -541,12 +503,12 @@ class CheckTypeHintsPassTest extends TestCase $container->register('foo', FooNotExisting::class); $container->register('bar', BarNotExisting::class) - ->setFactory(array( + ->setFactory([ new Reference('foo'), 'notExistingMethod', - )); + ]); - (new CheckTypeHintsPass())->process($container); + (new CheckTypeDeclarationsPass())->process($container); $this->addToAssertionCount(1); } @@ -558,12 +520,12 @@ class CheckTypeHintsPassTest extends TestCase $container->register('bar', BarNotExisting::class) ->addArgument(1); - (new CheckTypeHintsPass())->process($container); + (new CheckTypeDeclarationsPass())->process($container); $this->addToAssertionCount(1); } - public function testProcessDoesNotThrowsExceptionOnValidTypeHints() + public function testProcessDoesNotThrowsExceptionOnValidTypes() { $container = new ContainerBuilder(); @@ -571,7 +533,22 @@ class CheckTypeHintsPassTest extends TestCase $container->register('bar', Bar::class) ->addArgument(new Reference('foo')); - (new CheckTypeHintsPass(true))->process($container); + (new CheckTypeDeclarationsPass(true))->process($container); + + $this->assertInstanceOf(\stdClass::class, $container->get('bar')->foo); + } + + public function testProcessThrowsOnIterableTypeWhenScalarPassed() + { + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "bar_call": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\BarMethodCall::setIterable" accepts "iterable", "integer" passed.'); + + $container = new ContainerBuilder(); + + $container->register('bar_call', BarMethodCall::class) + ->addMethodCall('setIterable', [2]); + + (new CheckTypeDeclarationsPass(true))->process($container); $this->assertInstanceOf(\stdClass::class, $container->get('bar')->foo); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeHintsPass/Bar.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/Bar.php similarity index 88% rename from src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeHintsPass/Bar.php rename to src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/Bar.php index 85a1289815..403841ce88 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeHintsPass/Bar.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/Bar.php @@ -1,6 +1,6 @@ foo = $foo; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeHintsPass/BarOptionalArgument.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarOptionalArgument.php similarity index 89% rename from src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeHintsPass/BarOptionalArgument.php rename to src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarOptionalArgument.php index 3b6daa77f8..4f34889513 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeHintsPass/BarOptionalArgument.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarOptionalArgument.php @@ -1,6 +1,6 @@