Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / vendor / symfony / dependency-injection / Tests / Compiler / AutowirePassTest.php
index bc753a4655e4f7c13f7fb52b75b1ace0d14669d1..924a4909424924c7939c3cfc60f9c53e695f3a51 100644 (file)
 namespace Symfony\Component\DependencyInjection\Tests\Compiler;
 
 use PHPUnit\Framework\TestCase;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\Compiler\AutowireRequiredMethodsPass;
 use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
+use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic;
+use Symfony\Component\DependencyInjection\TypedReference;
+
+require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php';
 
 /**
  * @author Kévin Dunglas <dunglas@gmail.com>
@@ -26,15 +35,15 @@ class AutowirePassTest extends TestCase
     {
         $container = new ContainerBuilder();
 
-        $container->register('foo', __NAMESPACE__.'\Foo');
+        $container->register(Foo::class);
         $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
         $barDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(1, $container->getDefinition('bar')->getArguments());
-        $this->assertEquals('foo', (string) $container->getDefinition('bar')->getArgument(0));
+        $this->assertEquals(Foo::class, (string) $container->getDefinition('bar')->getArgument(0));
     }
 
     /**
@@ -43,47 +52,81 @@ class AutowirePassTest extends TestCase
     public function testProcessVariadic()
     {
         $container = new ContainerBuilder();
-        $container->register('foo', Foo::class);
+        $container->register(Foo::class);
         $definition = $container->register('fooVariadic', FooVariadic::class);
         $definition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(1, $container->getDefinition('fooVariadic')->getArguments());
-        $this->assertEquals('foo', (string) $container->getDefinition('fooVariadic')->getArgument(0));
+        $this->assertEquals(Foo::class, (string) $container->getDefinition('fooVariadic')->getArgument(0));
     }
 
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should alias the "Symfony\Component\DependencyInjection\Tests\Compiler\B" service to "Symfony\Component\DependencyInjection\Tests\Compiler\A" instead.
+     * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
+     * @expectedExceptionMessageInSymfony4 Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service.
+     */
     public function testProcessAutowireParent()
     {
         $container = new ContainerBuilder();
 
-        $container->register('b', __NAMESPACE__.'\B');
+        $container->register(B::class);
         $cDefinition = $container->register('c', __NAMESPACE__.'\C');
         $cDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(1, $container->getDefinition('c')->getArguments());
-        $this->assertEquals('b', (string) $container->getDefinition('c')->getArgument(0));
+        $this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0));
     }
 
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" to "Symfony\Component\DependencyInjection\Tests\Compiler\AInterface" instead.
+     * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
+     * @expectedExceptionMessageInSymfony4 Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service.
+     */
+    public function testProcessLegacyAutowireWithAvailableInterface()
+    {
+        $container = new ContainerBuilder();
+
+        $container->setAlias(AInterface::class, B::class);
+        $container->register(B::class);
+        $cDefinition = $container->register('c', __NAMESPACE__.'\C');
+        $cDefinition->setAutowired(true);
+
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
+
+        $this->assertCount(1, $container->getDefinition('c')->getArguments());
+        $this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0));
+    }
+
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should alias the "Symfony\Component\DependencyInjection\Tests\Compiler\F" service to "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" instead.
+     * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException
+     * @expectedExceptionMessageInSymfony4 Cannot autowire service "g": argument "$d" of method "Symfony\Component\DependencyInjection\Tests\Compiler\G::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" but no such service exists. You should maybe alias this interface to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\F" service.
+     */
     public function testProcessAutowireInterface()
     {
         $container = new ContainerBuilder();
 
-        $container->register('f', __NAMESPACE__.'\F');
+        $container->register(F::class);
         $gDefinition = $container->register('g', __NAMESPACE__.'\G');
         $gDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(3, $container->getDefinition('g')->getArguments());
-        $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0));
-        $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1));
-        $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(2));
+        $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(0));
+        $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(1));
+        $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(2));
     }
 
     public function testCompleteExistingDefinition()
@@ -91,38 +134,70 @@ class AutowirePassTest extends TestCase
         $container = new ContainerBuilder();
 
         $container->register('b', __NAMESPACE__.'\B');
-        $container->register('f', __NAMESPACE__.'\F');
+        $container->register(DInterface::class, F::class);
         $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b'));
         $hDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(2, $container->getDefinition('h')->getArguments());
         $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0));
-        $this->assertEquals('f', (string) $container->getDefinition('h')->getArgument(1));
+        $this->assertEquals(DInterface::class, (string) $container->getDefinition('h')->getArgument(1));
     }
 
     public function testCompleteExistingDefinitionWithNotDefinedArguments()
     {
         $container = new ContainerBuilder();
 
-        $container->register('b', __NAMESPACE__.'\B');
-        $container->register('f', __NAMESPACE__.'\F');
+        $container->register(B::class);
+        $container->register(DInterface::class, F::class);
         $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument('');
         $hDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(2, $container->getDefinition('h')->getArguments());
-        $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0));
-        $this->assertEquals('f', (string) $container->getDefinition('h')->getArgument(1));
+        $this->assertEquals(B::class, (string) $container->getDefinition('h')->getArgument(0));
+        $this->assertEquals(DInterface::class, (string) $container->getDefinition('h')->getArgument(1));
+    }
+
+    /**
+     * @group legacy
+     */
+    public function testExceptionsAreStored()
+    {
+        $container = new ContainerBuilder();
+
+        $container->register('c1', __NAMESPACE__.'\CollisionA');
+        $container->register('c2', __NAMESPACE__.'\CollisionB');
+        $container->register('c3', __NAMESPACE__.'\CollisionB');
+        $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
+        $aDefinition->setAutowired(true);
+
+        $pass = new AutowirePass(false);
+        $pass->process($container);
+        $this->assertCount(1, $pass->getAutowiringExceptions());
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (c1, c2, c3).
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Invalid service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public.
+     */
+    public function testPrivateConstructorThrowsAutowireException()
+    {
+        $container = new ContainerBuilder();
+
+        $container->autowire('private_service', __NAMESPACE__.'\PrivateConstructor');
+
+        $pass = new AutowirePass(true);
+        $pass->process($container);
+    }
+
+    /**
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2", "c3".
      */
     public function testTypeCollision()
     {
@@ -139,8 +214,8 @@ class AutowirePassTest extends TestCase
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Multiple services exist for this class (a1, a2).
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".
      */
     public function testTypeNotGuessable()
     {
@@ -156,8 +231,8 @@ class AutowirePassTest extends TestCase
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Multiple services exist for this class (a1, a2).
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".
      */
     public function testTypeNotGuessableWithSubclass()
     {
@@ -173,8 +248,8 @@ class AutowirePassTest extends TestCase
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". No services were found matching this interface and it cannot be auto-registered.
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists.
      */
     public function testTypeNotGuessableNoServicesFound()
     {
@@ -193,7 +268,7 @@ class AutowirePassTest extends TestCase
 
         $container->register('a1', __NAMESPACE__.'\Foo');
         $container->register('a2', __NAMESPACE__.'\Foo');
-        $container->register('a3', __NAMESPACE__.'\Foo')->addAutowiringType(__NAMESPACE__.'\Foo');
+        $container->register(Foo::class, Foo::class);
         $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument');
         $aDefinition->setAutowired(true);
 
@@ -201,7 +276,7 @@ class AutowirePassTest extends TestCase
         $pass->process($container);
 
         $this->assertCount(1, $container->getDefinition('a')->getArguments());
-        $this->assertEquals('a3', (string) $container->getDefinition('a')->getArgument(0));
+        $this->assertEquals(Foo::class, (string) $container->getDefinition('a')->getArgument(0));
     }
 
     public function testWithTypeSet()
@@ -209,7 +284,8 @@ class AutowirePassTest extends TestCase
         $container = new ContainerBuilder();
 
         $container->register('c1', __NAMESPACE__.'\CollisionA');
-        $container->register('c2', __NAMESPACE__.'\CollisionB')->addAutowiringType(__NAMESPACE__.'\CollisionInterface');
+        $container->register('c2', __NAMESPACE__.'\CollisionB');
+        $container->setAlias(CollisionInterface::class, 'c2');
         $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
         $aDefinition->setAutowired(true);
 
@@ -217,9 +293,14 @@ class AutowirePassTest extends TestCase
         $pass->process($container);
 
         $this->assertCount(1, $container->getDefinition('a')->getArguments());
-        $this->assertEquals('c2', (string) $container->getDefinition('a')->getArgument(0));
+        $this->assertEquals(CollisionInterface::class, (string) $container->getDefinition('a')->getArgument(0));
     }
 
+    /**
+     * @group legacy
+     * @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" is deprecated since Symfony 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" instead.
+     * @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" is deprecated since Symfony 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" instead.
+     */
     public function testCreateDefinition()
     {
         $container = new ContainerBuilder();
@@ -231,14 +312,14 @@ class AutowirePassTest extends TestCase
         $pass->process($container);
 
         $this->assertCount(2, $container->getDefinition('coop_tilleuls')->getArguments());
-        $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0));
-        $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas', $container->getDefinition('coop_tilleuls')->getArgument(1));
+        $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0));
+        $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas', $container->getDefinition('coop_tilleuls')->getArgument(1));
 
         $dunglasDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas');
         $this->assertEquals(__NAMESPACE__.'\Dunglas', $dunglasDefinition->getClass());
         $this->assertFalse($dunglasDefinition->isPublic());
         $this->assertCount(1, $dunglasDefinition->getArguments());
-        $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\lille', $dunglasDefinition->getArgument(0));
+        $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille', $dunglasDefinition->getArgument(0));
 
         $lilleDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille');
         $this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
@@ -248,51 +329,51 @@ class AutowirePassTest extends TestCase
     {
         $container = new ContainerBuilder();
 
-        $container->setParameter('class_name', __NAMESPACE__.'\Foo');
-        $container->register('foo', '%class_name%');
-        $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
+        $container->setParameter('class_name', Bar::class);
+        $container->register(Foo::class);
+        $barDefinition = $container->register('bar', '%class_name%');
         $barDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
-        $this->assertEquals('foo', $container->getDefinition('bar')->getArgument(0));
+        $this->assertEquals(Foo::class, $container->getDefinition('bar')->getArgument(0));
     }
 
     public function testOptionalParameter()
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('foo', __NAMESPACE__.'\Foo');
+        $container->register(A::class);
+        $container->register(Foo::class);
         $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter');
         $optDefinition->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $definition = $container->getDefinition('opt');
         $this->assertNull($definition->getArgument(0));
-        $this->assertEquals('a', $definition->getArgument(1));
-        $this->assertEquals('foo', $definition->getArgument(2));
+        $this->assertEquals(A::class, $definition->getArgument(1));
+        $this->assertEquals(Foo::class, $definition->getArgument(2));
     }
 
     public function testDontTriggerAutowiring()
     {
         $container = new ContainerBuilder();
 
-        $container->register('foo', __NAMESPACE__.'\Foo');
+        $container->register(Foo::class);
         $container->register('bar', __NAMESPACE__.'\Bar');
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $this->assertCount(0, $container->getDefinition('bar')->getArguments());
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Cannot autowire argument 2 for Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument because the type-hinted class does not exist (Class Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass does not exist).
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class was not found.
      */
     public function testClassNotFoundThrowsException()
     {
@@ -301,13 +382,15 @@ class AutowirePassTest extends TestCase
         $aDefinition = $container->register('a', __NAMESPACE__.'\BadTypeHintedArgument');
         $aDefinition->setAutowired(true);
 
+        $container->register(Dunglas::class, Dunglas::class);
+
         $pass = new AutowirePass();
         $pass->process($container);
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Cannot autowire argument 2 for Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument because the type-hinted class does not exist (Class Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass does not exist).
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class is missing a parent class (Class Symfony\Bug\NotExistClass not found).
      */
     public function testParentClassNotFoundThrowsException()
     {
@@ -316,109 +399,130 @@ class AutowirePassTest extends TestCase
         $aDefinition = $container->register('a', __NAMESPACE__.'\BadParentTypeHintedArgument');
         $aDefinition->setAutowired(true);
 
+        $container->register(Dunglas::class, Dunglas::class);
+
         $pass = new AutowirePass();
         $pass->process($container);
     }
 
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead.
+     * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. You should maybe alias this class to the existing "foo" service.
+     */
     public function testDontUseAbstractServices()
     {
         $container = new ContainerBuilder();
 
-        $container->register('abstract_foo', __NAMESPACE__.'\Foo')->setAbstract(true);
+        $container->register(Foo::class)->setAbstract(true);
         $container->register('foo', __NAMESPACE__.'\Foo');
         $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
-
-        $arguments = $container->getDefinition('bar')->getArguments();
-        $this->assertSame('foo', (string) $arguments[0]);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
     }
 
     public function testSomeSpecificArgumentsAreSet()
     {
         $container = new ContainerBuilder();
 
-        $container->register('foo', __NAMESPACE__.'\Foo');
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('dunglas', __NAMESPACE__.'\Dunglas');
+        $container->register('foo', Foo::class);
+        $container->register(A::class);
+        $container->register(Dunglas::class);
         $container->register('multiple', __NAMESPACE__.'\MultipleArguments')
             ->setAutowired(true)
             // set the 2nd (index 1) argument only: autowire the first and third
             // args are: A, Foo, Dunglas
             ->setArguments(array(
                 1 => new Reference('foo'),
+                3 => array('bar'),
             ));
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $definition = $container->getDefinition('multiple');
         $this->assertEquals(
             array(
-                new Reference('a'),
+                new TypedReference(A::class, A::class, MultipleArguments::class),
                 new Reference('foo'),
-                new Reference('dunglas'),
+                new TypedReference(Dunglas::class, Dunglas::class, MultipleArguments::class),
+                array('bar'),
             ),
             $definition->getArguments()
         );
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Unable to autowire argument index 1 ($foo) for the service "arg_no_type_hint". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$bar" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" is type-hinted "array", you should configure its value explicitly.
      */
     public function testScalarArgsCannotBeAutowired()
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('dunglas', __NAMESPACE__.'\Dunglas');
+        $container->register(A::class);
+        $container->register(Dunglas::class);
         $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
+            ->setArguments(array(1 => 'foo'))
             ->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
-
-        $container->getDefinition('arg_no_type_hint');
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
     }
 
     /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Unable to autowire argument index 1 ($foo) for the service "not_really_optional_scalar". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" has no type-hint, you should configure its value explicitly.
      */
-    public function testOptionalScalarNotReallyOptionalThrowException()
+    public function testNoTypeArgsCannotBeAutowired()
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('lille', __NAMESPACE__.'\Lille');
-        $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional')
+        $container->register(A::class);
+        $container->register(Dunglas::class);
+        $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
             ->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
+    }
+
+    public function testOptionalScalarNotReallyOptionalUsesDefaultValue()
+    {
+        $container = new ContainerBuilder();
+
+        $container->register(A::class);
+        $container->register(Lille::class);
+        $definition = $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional')
+            ->setAutowired(true);
+
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
+
+        $this->assertSame('default_val', $definition->getArgument(1));
     }
 
     public function testOptionalScalarArgsDontMessUpOrder()
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('lille', __NAMESPACE__.'\Lille');
+        $container->register(A::class);
+        $container->register(Lille::class);
         $container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
             ->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $definition = $container->getDefinition('with_optional_scalar');
         $this->assertEquals(
             array(
-                new Reference('a'),
+                new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalar::class),
                 // use the default value
                 'default_val',
-                new Reference('lille'),
+                new TypedReference(Lille::class, Lille::class),
             ),
             $definition->getArguments()
         );
@@ -428,26 +532,131 @@ class AutowirePassTest extends TestCase
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('lille', __NAMESPACE__.'\Lille');
+        $container->register(A::class);
+        $container->register(Lille::class);
         $container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast')
             ->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
         $definition = $container->getDefinition('with_optional_scalar_last');
         $this->assertEquals(
             array(
-                new Reference('a'),
-                new Reference('lille'),
+                new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalarLast::class),
+                new TypedReference(Lille::class, Lille::class, MultipleArgumentsOptionalScalarLast::class),
             ),
             $definition->getArguments()
         );
     }
 
+    public function testOptionalArgsNoRequiredForCoreClasses()
+    {
+        $container = new ContainerBuilder();
+
+        $container->register('foo', \SplFileObject::class)
+            ->addArgument('foo.txt')
+            ->setAutowired(true);
+
+        (new AutowirePass())->process($container);
+
+        $definition = $container->getDefinition('foo');
+        $this->assertEquals(
+            array('foo.txt'),
+            $definition->getArguments()
+        );
+    }
+
+    public function testSetterInjection()
+    {
+        $container = new ContainerBuilder();
+        $container->register(Foo::class);
+        $container->register(A::class);
+        $container->register(CollisionA::class);
+        $container->register(CollisionB::class);
+
+        // manually configure *one* call, to override autowiring
+        $container
+            ->register('setter_injection', SetterInjection::class)
+            ->setAutowired(true)
+            ->addMethodCall('setWithCallsConfigured', array('manual_arg1', 'manual_arg2'))
+        ;
+
+        (new ResolveClassPass())->process($container);
+        (new AutowireRequiredMethodsPass())->process($container);
+        (new AutowirePass())->process($container);
+
+        $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls();
+
+        $this->assertEquals(
+            array('setWithCallsConfigured', 'setFoo', 'setDependencies', 'setChildMethodWithoutDocBlock'),
+            array_column($methodCalls, 0)
+        );
+
+        // test setWithCallsConfigured args
+        $this->assertEquals(
+            array('manual_arg1', 'manual_arg2'),
+            $methodCalls[0][1]
+        );
+        // test setFoo args
+        $this->assertEquals(
+            array(new TypedReference(Foo::class, Foo::class, SetterInjection::class)),
+            $methodCalls[1][1]
+        );
+    }
+
+    public function testExplicitMethodInjection()
+    {
+        $container = new ContainerBuilder();
+        $container->register(Foo::class);
+        $container->register(A::class);
+        $container->register(CollisionA::class);
+        $container->register(CollisionB::class);
+
+        $container
+            ->register('setter_injection', SetterInjection::class)
+            ->setAutowired(true)
+            ->addMethodCall('notASetter', array())
+        ;
+
+        (new ResolveClassPass())->process($container);
+        (new AutowireRequiredMethodsPass())->process($container);
+        (new AutowirePass())->process($container);
+
+        $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls();
+
+        $this->assertEquals(
+            array('notASetter', 'setFoo', 'setDependencies', 'setWithCallsConfigured', 'setChildMethodWithoutDocBlock'),
+            array_column($methodCalls, 0)
+        );
+        $this->assertEquals(
+            array(new TypedReference(A::class, A::class, SetterInjection::class)),
+            $methodCalls[0][1]
+        );
+    }
+
+    /**
+     * @group legacy
+     * @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\A" is deprecated since Symfony 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\A" instead.
+     */
+    public function testTypedReference()
+    {
+        $container = new ContainerBuilder();
+
+        $container
+            ->register('bar', Bar::class)
+            ->setProperty('a', array(new TypedReference(A::class, A::class, Bar::class)))
+        ;
+
+        $pass = new AutowirePass();
+        $pass->process($container);
+
+        $this->assertSame(A::class, $container->getDefinition('autowired.'.A::class)->getClass());
+    }
+
     /**
      * @dataProvider getCreateResourceTests
+     * @group legacy
      */
     public function testCreateResourceForClass($className, $isEqual)
     {
@@ -488,12 +697,59 @@ class AutowirePassTest extends TestCase
         $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
         $barDefinition->setAutowired(true);
 
+        $container->register(Foo::class, Foo::class);
+
         $pass = new AutowirePass();
         $pass->process($container);
 
         $this->assertTrue($container->hasDefinition('bar'));
     }
 
+    public function testSetterInjectionCollisionThrowsException()
+    {
+        $container = new ContainerBuilder();
+
+        $container->register('c1', CollisionA::class);
+        $container->register('c2', CollisionB::class);
+        $aDefinition = $container->register('setter_injection_collision', SetterInjectionCollision::class);
+        $aDefinition->setAutowired(true);
+
+        (new AutowireRequiredMethodsPass())->process($container);
+
+        $pass = new AutowirePass();
+
+        try {
+            $pass->process($container);
+        } catch (AutowiringFailedException $e) {
+        }
+
+        $this->assertNotNull($e);
+        $this->assertSame('Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2".', $e->getMessage());
+    }
+
+    /**
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "my_service": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\K::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" but no such service exists. Did you create a class that implements this interface?
+     */
+    public function testInterfaceWithNoImplementationSuggestToWriteOne()
+    {
+        $container = new ContainerBuilder();
+
+        $aDefinition = $container->register('my_service', K::class);
+        $aDefinition->setAutowired(true);
+
+        (new AutowireRequiredMethodsPass())->process($container);
+
+        $pass = new AutowirePass();
+        $pass->process($container);
+    }
+
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead.
+     * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to the existing "foo" service.
+     */
     public function testProcessDoesNotTriggerDeprecations()
     {
         $container = new ContainerBuilder();
@@ -513,230 +769,159 @@ class AutowirePassTest extends TestCase
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A');
-        $container->register('lille', __NAMESPACE__.'\Lille');
+        $container->register(A::class);
+        $container->register(Lille::class);
         $container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
             ->setAutowired(true)
             ->setArguments(array('', ''));
 
-        $pass = new AutowirePass();
-        $pass->process($container);
-
-        $this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments());
-    }
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
-    public function provideAutodiscoveredAutowiringOrder()
-    {
-        return array(
-            array('CannotBeAutowiredForwardOrder'),
-            array('CannotBeAutowiredReverseOrder'),
-        );
+        $this->assertEquals(array(new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalar::class), '', new TypedReference(Lille::class, Lille::class)), $container->getDefinition('foo')->getArguments());
     }
 
-    /**
-     * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
-     * @expectedExceptionMessage Service "a" can use either autowiring or a factory, not both.
-     */
     public function testWithFactory()
     {
         $container = new ContainerBuilder();
 
-        $container->register('a', __NAMESPACE__.'\A')
-            ->setFactory('foo')
+        $container->register(Foo::class);
+        $definition = $container->register('a', A::class)
+            ->setFactory(array(A::class, 'create'))
             ->setAutowired(true);
 
-        $pass = new AutowirePass();
-        $pass->process($container);
-    }
-}
-
-class Foo
-{
-}
+        (new ResolveClassPass())->process($container);
+        (new AutowirePass())->process($container);
 
-class Bar
-{
-    public function __construct(Foo $foo)
-    {
+        $this->assertEquals(array(new TypedReference(Foo::class, Foo::class, A::class)), $definition->getArguments());
     }
-}
 
-class A
-{
-}
-
-class B extends A
-{
-}
-
-class C
-{
-    public function __construct(A $a)
+    /**
+     * @dataProvider provideNotWireableCalls
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     */
+    public function testNotWireableCalls($method, $expectedMsg)
     {
-    }
-}
-
-interface DInterface
-{
-}
-
-interface EInterface extends DInterface
-{
-}
+        $container = new ContainerBuilder();
 
-interface IInterface
-{
-}
+        $foo = $container->register('foo', NotWireable::class)->setAutowired(true)
+            ->addMethodCall('setBar', array())
+            ->addMethodCall('setOptionalNotAutowireable', array())
+            ->addMethodCall('setOptionalNoTypeHint', array())
+            ->addMethodCall('setOptionalArgNoAutowireable', array())
+        ;
 
-class I implements IInterface
-{
-}
+        if ($method) {
+            $foo->addMethodCall($method, array());
+        }
 
-class F extends I implements EInterface
-{
-}
+        if (method_exists($this, 'expectException')) {
+            $this->expectException(RuntimeException::class);
+            $this->expectExceptionMessage($expectedMsg);
+        } else {
+            $this->setExpectedException(RuntimeException::class, $expectedMsg);
+        }
 
-class G
-{
-    public function __construct(DInterface $d, EInterface $e, IInterface $i)
-    {
+        (new ResolveClassPass())->process($container);
+        (new AutowireRequiredMethodsPass())->process($container);
+        (new AutowirePass())->process($container);
     }
-}
 
-class H
-{
-    public function __construct(B $b, DInterface $d)
+    public function provideNotWireableCalls()
     {
+        return array(
+            array('setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class was not found.'),
+            array('setDifferentNamespace', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setDifferentNamespace()" references class "stdClass" but no such service exists. It cannot be auto-registered because it is from a different root namespace.'),
+            array(null, 'Invalid service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'),
+        );
     }
-}
-
-interface CollisionInterface
-{
-}
 
-class CollisionA implements CollisionInterface
-{
-}
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
+     * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessageInSymfony4 Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
+     */
+    public function testByIdAlternative()
+    {
+        $container = new ContainerBuilder();
 
-class CollisionB implements CollisionInterface
-{
-}
+        $container->setAlias(IInterface::class, 'i');
+        $container->register('i', I::class);
+        $container->register('j', J::class)
+            ->setAutowired(true);
 
-class CannotBeAutowired
-{
-    public function __construct(CollisionInterface $collision)
-    {
+        $pass = new AutowirePass();
+        $pass->process($container);
     }
-}
 
-class CannotBeAutowiredForwardOrder
-{
-    public function __construct(CollisionA $a, CollisionInterface $b, CollisionB $c)
+    /**
+     * @group legacy
+     * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for "Symfony\Component\DependencyInjection\Tests\Compiler\A" in "Symfony\Component\DependencyInjection\Tests\Compiler\Bar" to "Symfony\Component\DependencyInjection\Tests\Compiler\AInterface" instead.
+     */
+    public function testTypedReferenceDeprecationNotice()
     {
+        $container = new ContainerBuilder();
+
+        $container->register('aClass', A::class);
+        $container->setAlias(AInterface::class, 'aClass');
+        $container
+            ->register('bar', Bar::class)
+            ->setProperty('a', array(new TypedReference(A::class, A::class, Bar::class)))
+        ;
+
+        $pass = new AutowirePass();
+        $pass->process($container);
     }
-}
 
-class CannotBeAutowiredReverseOrder
-{
-    public function __construct(CollisionA $a, CollisionB $c, CollisionInterface $b)
+    /**
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.
+     */
+    public function testExceptionWhenAliasExists()
     {
-    }
-}
+        $container = new ContainerBuilder();
 
-class Lille
-{
-}
+        // multiple I services... but there *is* IInterface available
+        $container->setAlias(IInterface::class, 'i');
+        $container->register('i', I::class);
+        $container->register('i2', I::class);
+        // J type-hints against I concretely
+        $container->register('j', J::class)
+            ->setAutowired(true);
 
-class Dunglas
-{
-    public function __construct(Lille $l)
-    {
+        $pass = new AutowirePass();
+        $pass->process($container);
     }
-}
 
-class LesTilleuls
-{
-    public function __construct(Dunglas $j, Dunglas $k)
+    /**
+     * @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
+     * @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. You should maybe alias this class to one of these existing services: "i", "i2".
+     */
+    public function testExceptionWhenAliasDoesNotExist()
     {
-    }
-}
+        $container = new ContainerBuilder();
 
-class OptionalParameter
-{
-    public function __construct(CollisionInterface $c = null, A $a, Foo $f = null)
-    {
-    }
-}
+        // multiple I instances... but no IInterface alias
+        $container->register('i', I::class);
+        $container->register('i2', I::class);
+        // J type-hints against I concretely
+        $container->register('j', J::class)
+            ->setAutowired(true);
 
-class BadTypeHintedArgument
-{
-    public function __construct(Dunglas $k, NotARealClass $r)
-    {
-    }
-}
-class BadParentTypeHintedArgument
-{
-    public function __construct(Dunglas $k, OptionalServiceClass $r)
-    {
-    }
-}
-class NotGuessableArgument
-{
-    public function __construct(Foo $k)
-    {
-    }
-}
-class NotGuessableArgumentForSubclass
-{
-    public function __construct(A $k)
-    {
-    }
-}
-class MultipleArguments
-{
-    public function __construct(A $k, $foo, Dunglas $dunglas)
-    {
+        $pass = new AutowirePass();
+        $pass->process($container);
     }
-}
 
-class MultipleArgumentsOptionalScalar
-{
-    public function __construct(A $a, $foo = 'default_val', Lille $lille = null)
-    {
-    }
-}
-class MultipleArgumentsOptionalScalarLast
-{
-    public function __construct(A $a, Lille $lille, $foo = 'some_val')
-    {
-    }
-}
-class MultipleArgumentsOptionalScalarNotReallyOptional
-{
-    public function __construct(A $a, $foo = 'default_val', Lille $lille)
+    public function testInlineServicesAreNotCandidates()
     {
-    }
-}
+        $container = new ContainerBuilder();
+        $loader = new XmlFileLoader($container, new FileLocator(realpath(__DIR__.'/../Fixtures/xml')));
+        $loader->load('services_inline_not_candidate.xml');
 
-/*
- * Classes used for testing createResourceForClass
- */
-class ClassForResource
-{
-    public function __construct($foo, Bar $bar = null)
-    {
-    }
+        $pass = new AutowirePass();
+        $pass->process($container);
 
-    public function setBar(Bar $bar)
-    {
-    }
-}
-class IdenticalClassResource extends ClassForResource
-{
-}
-class ClassChangedConstructorArgs extends ClassForResource
-{
-    public function __construct($foo, Bar $bar, $baz)
-    {
+        $this->assertSame(array(), $container->getDefinition('autowired')->getArguments());
     }
 }