From d48d9c9271322e25e7d608d1a5c98c668e4072cf Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Thu, 9 Apr 2015 15:56:37 +0100
Subject: [PATCH] Issue #2448605 by martin107, willzyx, tim.plunkett, klausi,
 dpopdan: Replace usages of drupal_get_destination() with the redirect
 destination service

---
 core/core.services.yml                        |  4 +-
 .../Drupal/Core/Controller/ControllerBase.php |  5 +-
 .../CustomPageExceptionHtmlSubscriber.php     |  7 +-
 .../DefaultExceptionHtmlSubscriber.php        | 24 ++++---
 core/lib/Drupal/Core/Form/FormBase.php        |  5 +-
 .../Core/Render/Element/SystemCompactLink.php |  4 +-
 .../Core/Routing/RedirectDestinationTrait.php | 72 +++++++++++++++++++
 .../book/src/Form/BookAdminEditForm.php       |  2 +-
 core/modules/comment/src/CommentManager.php   |  2 +-
 .../comment/src/Form/CommentAdminOverview.php |  2 +-
 .../comment/src/Plugin/views/field/Link.php   |  3 +
 .../src/Plugin/views/field/LinkApprove.php    |  2 +-
 .../src/Plugin/views/field/LinkDelete.php     |  2 +-
 .../src/Plugin/views/field/LinkEdit.php       |  2 +-
 .../content_translation.module                |  2 +-
 .../Plugin/views/field/ContextualLinks.php    |  5 +-
 .../field_ui/src/Form/FieldStorageAddForm.php |  2 +-
 .../forum/src/Controller/ForumController.php  |  9 +--
 core/modules/locale/locale.pages.inc          |  2 +-
 core/modules/menu_ui/src/MenuForm.php         |  4 +-
 core/modules/node/src/NodeListBuilder.php     | 18 ++++-
 .../node/src/Plugin/views/field/Link.php      |  3 +
 .../src/Plugin/views/field/LinkDelete.php     |  2 +-
 .../node/src/Plugin/views/field/LinkEdit.php  |  2 +-
 .../src/Plugin/views/field/RevisionLink.php   |  2 +-
 .../Plugin/views/field/RevisionLinkDelete.php |  2 +-
 .../Plugin/views/field/RevisionLinkRevert.php |  2 +-
 .../path/src/Controller/PathController.php    |  2 +-
 core/modules/path/src/Form/EditForm.php       |  2 +-
 core/modules/shortcut/shortcut.module         |  2 +-
 .../src/Plugin/views/field/BulkForm.php       |  5 +-
 core/modules/system/system.module             |  2 +-
 .../src/Controller/CommonTestController.php   |  3 +-
 .../taxonomy/src/Form/OverviewTerms.php       |  2 +-
 .../src/Plugin/views/field/LinkEdit.php       |  5 +-
 core/modules/update/update.module             |  4 +-
 .../user/src/Plugin/Block/UserLoginBlock.php  |  4 +-
 .../user/src/Plugin/views/field/Link.php      |  3 +
 .../src/Plugin/views/field/LinkCancel.php     |  2 +-
 .../user/src/Plugin/views/field/LinkEdit.php  |  2 +-
 core/modules/user/src/UserListBuilder.php     | 18 ++++-
 core/modules/user/user.api.php                |  2 +-
 .../src/Controller/ViewAjaxController.php     |  2 +-
 .../Plugin/views/field/EntityOperations.php   |  5 +-
 .../views/src/Plugin/views/field/Links.php    |  2 +-
 .../Controller/ViewAjaxControllerTest.php     |  9 ---
 .../views/field/EntityOperationsUnitTest.php  | 21 +++---
 .../CustomPageExceptionHtmlSubscriberTest.php | 25 ++++---
 48 files changed, 213 insertions(+), 100 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Routing/RedirectDestinationTrait.php

diff --git a/core/core.services.yml b/core/core.services.yml
index f98c9f269ef6..18d34b90a070 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -989,7 +989,7 @@ services:
     class: Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber
     tags:
       - { name: event_subscriber }
-    arguments: ['@http_kernel', '@logger.channel.php']
+    arguments: ['@http_kernel', '@logger.channel.php', '@redirect.destination']
   exception.default:
     class: Drupal\Core\EventSubscriber\DefaultExceptionSubscriber
     tags:
@@ -1009,7 +1009,7 @@ services:
     class: Drupal\Core\EventSubscriber\CustomPageExceptionHtmlSubscriber
     tags:
       - { name: event_subscriber }
-    arguments: ['@config.factory', '@path.alias_manager', '@http_kernel', '@logger.channel.php']
+    arguments: ['@config.factory', '@path.alias_manager', '@http_kernel', '@logger.channel.php', '@redirect.destination']
   exception.fast_404_html:
     class: Drupal\Core\EventSubscriber\Fast404ExceptionHtmlSubscriber
     tags:
diff --git a/core/lib/Drupal/Core/Controller/ControllerBase.php b/core/lib/Drupal/Core/Controller/ControllerBase.php
index 9e5abdf45f75..bb17a365027d 100644
--- a/core/lib/Drupal/Core/Controller/ControllerBase.php
+++ b/core/lib/Drupal/Core/Controller/ControllerBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Routing\LinkGeneratorTrait;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Routing\UrlGeneratorTrait;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -35,8 +36,10 @@
  * @ingroup menu
  */
 abstract class ControllerBase implements ContainerInjectionInterface {
-  use StringTranslationTrait;
+
   use LinkGeneratorTrait;
+  use RedirectDestinationTrait;
+  use StringTranslationTrait;
   use UrlGeneratorTrait;
 
   /**
diff --git a/core/lib/Drupal/Core/EventSubscriber/CustomPageExceptionHtmlSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/CustomPageExceptionHtmlSubscriber.php
index c393a343983f..377f26bccfe1 100644
--- a/core/lib/Drupal/Core/EventSubscriber/CustomPageExceptionHtmlSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/CustomPageExceptionHtmlSubscriber.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Path\AliasManagerInterface;
+use Drupal\Core\Routing\RedirectDestinationInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
@@ -44,9 +45,11 @@ class CustomPageExceptionHtmlSubscriber extends DefaultExceptionHtmlSubscriber {
    *   The HTTP Kernel service.
    * @param \Psr\Log\LoggerInterface $logger
    *   The logger service.
+   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
+   *   The redirect destination service.
    */
-  public function __construct(ConfigFactoryInterface $config_factory, AliasManagerInterface $alias_manager, HttpKernelInterface $http_kernel, LoggerInterface $logger) {
-    parent::__construct($http_kernel, $logger);
+  public function __construct(ConfigFactoryInterface $config_factory, AliasManagerInterface $alias_manager, HttpKernelInterface $http_kernel, LoggerInterface $logger, RedirectDestinationInterface $redirect_destination) {
+    parent::__construct($http_kernel, $logger, $redirect_destination);
     $this->configFactory = $config_factory;
     $this->aliasManager = $alias_manager;
   }
diff --git a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php
index f5a4b798556b..fc5375c50dd5 100644
--- a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionHtmlSubscriber.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\EventSubscriber;
 
 use Drupal\Core\Routing\AccessAwareRouterInterface;
+use Drupal\Core\Routing\RedirectDestinationInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Utility\Error;
 use Psr\Log\LoggerInterface;
@@ -35,6 +36,13 @@ class DefaultExceptionHtmlSubscriber extends HttpExceptionSubscriberBase {
    */
   protected $logger;
 
+  /**
+   * The redirect destination service.
+   *
+   * @var \Drupal\Core\Routing\RedirectDestinationInterface
+   */
+  protected $redirectDestination;
+
   /**
    * Constructs a new DefaultExceptionHtmlSubscriber.
    *
@@ -42,10 +50,13 @@ class DefaultExceptionHtmlSubscriber extends HttpExceptionSubscriberBase {
    *   The HTTP kernel.
    * @param \Psr\Log\LoggerInterface $logger
    *   The logger service.
+   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
+   *   The redirect destination service.
    */
-  public function __construct(HttpKernelInterface $http_kernel, LoggerInterface $logger) {
+  public function __construct(HttpKernelInterface $http_kernel, LoggerInterface $logger, RedirectDestinationInterface $redirect_destination) {
     $this->httpKernel = $http_kernel;
     $this->logger = $logger;
+    $this->redirectDestination = $redirect_destination;
   }
 
   /**
@@ -105,10 +116,10 @@ protected function makeSubrequest(GetResponseForExceptionEvent $event, $url, $st
 
     if ($url != $request->getBasePath() . '/' && $url != $current_url) {
       if ($request->getMethod() === 'POST') {
-        $sub_request = Request::create($url, 'POST', $this->drupalGetDestination() + ['_exception_statuscode' => $status_code] + $request->request->all(), $request->cookies->all(), [], $request->server->all());
+        $sub_request = Request::create($url, 'POST', $this->redirectDestination->getAsArray() + ['_exception_statuscode' => $status_code] + $request->request->all(), $request->cookies->all(), [], $request->server->all());
       }
       else {
-        $sub_request = Request::create($url, 'GET', $request->query->all() + $this->drupalGetDestination() + ['_exception_statuscode' => $status_code], $request->cookies->all(), [], $request->server->all());
+        $sub_request = Request::create($url, 'GET', $request->query->all() + $this->redirectDestination->getAsArray() + ['_exception_statuscode' => $status_code], $request->cookies->all(), [], $request->server->all());
       }
 
       try {
@@ -137,11 +148,4 @@ protected function makeSubrequest(GetResponseForExceptionEvent $event, $url, $st
     }
   }
 
-  /**
-   * Wraps drupal_get_destination().
-   */
-  protected function drupalGetDestination() {
-    return drupal_get_destination();
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Form/FormBase.php b/core/lib/Drupal/Core/Form/FormBase.php
index d7c2bfde84ae..5c2d2af34f22 100644
--- a/core/lib/Drupal/Core/Form/FormBase.php
+++ b/core/lib/Drupal/Core/Form/FormBase.php
@@ -11,6 +11,7 @@
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Routing\LinkGeneratorTrait;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Routing\UrlGeneratorTrait;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -22,9 +23,11 @@
  * @ingroup form_api
  */
 abstract class FormBase implements FormInterface, ContainerInjectionInterface {
-  use StringTranslationTrait;
+
   use DependencySerializationTrait;
   use LinkGeneratorTrait;
+  use RedirectDestinationTrait;
+  use StringTranslationTrait;
   use UrlGeneratorTrait;
 
   /**
diff --git a/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php b/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php
index c561b38fb133..fa701b0d06e1 100644
--- a/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php
+++ b/core/lib/Drupal/Core/Render/Element/SystemCompactLink.php
@@ -63,7 +63,7 @@ public static function preRenderCompactLink($element) {
       $element['#url'] = BaseUrl::fromRoute('system.admin_compact_page', array('mode' => 'off'));
       $element['#options'] = array(
         'attributes' => array('title' => t('Expand layout to include descriptions.')),
-        'query' => drupal_get_destination(),
+        'query' => \Drupal::destination()->getAsArray()
       );
     }
     else {
@@ -71,7 +71,7 @@ public static function preRenderCompactLink($element) {
       $element['#url'] = BaseUrl::fromRoute('system.admin_compact_page', array('mode' => 'on'));
       $element['#options'] = array(
         'attributes' => array('title' => t('Compress layout by hiding descriptions.')),
-        'query' => drupal_get_destination(),
+        'query' => \Drupal::destination()->getAsArray(),
       );
     }
 
diff --git a/core/lib/Drupal/Core/Routing/RedirectDestinationTrait.php b/core/lib/Drupal/Core/Routing/RedirectDestinationTrait.php
new file mode 100644
index 000000000000..db4696eea581
--- /dev/null
+++ b/core/lib/Drupal/Core/Routing/RedirectDestinationTrait.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Routing\RedirectDestinationTrait.
+ */
+
+namespace Drupal\Core\Routing;
+
+/**
+ * Wrapper methods for the Redirect Destination.
+ *
+ * This utility trait should only be used in application-level code, such as
+ * classes that would implement ContainerInjectionInterface. Services registered
+ * in the Container should not use this trait but inject the appropriate service
+ * directly for easier testing.
+ */
+trait RedirectDestinationTrait {
+
+  /**
+   * The redirect destination service.
+   *
+   * @var \Drupal\Core\Routing\RedirectDestinationInterface
+   */
+  protected $redirectDestination;
+
+  /**
+   * Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
+   *
+   * @see \Drupal\Core\Routing\RedirectDestinationInterface::getAsArray()
+   *
+   * @return array
+   *   An associative array containing the key:
+   *   - destination: The value of the current request's 'destination' query
+   *     parameter, if present. This can be either a relative or absolute URL.
+   *     However, for security, redirection to external URLs is not performed.
+   *     If the query parameter isn't present, then the URL of the current
+   *     request is returned.
+   */
+  protected function getDestinationArray() {
+    return $this->getRedirectDestination()->getAsArray();
+  }
+
+  /**
+   * Returns the redirect destination service.
+   *
+   * @return \Drupal\Core\Routing\RedirectDestinationInterface
+   *   The redirect destination helper.
+   */
+  protected function getRedirectDestination() {
+    if (!isset($this->redirectDestination)) {
+      $this->redirectDestination = \Drupal::destination();
+    }
+
+    return $this->redirectDestination;
+  }
+
+  /**
+   * Sets the redirect destination service.
+   *
+   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
+   *   The redirect destination service.
+   *
+   * @return $this
+   */
+  public function setRedirectDestination(RedirectDestinationInterface $redirect_destination) {
+    $this->redirectDestination = $redirect_destination;
+
+    return $this;
+  }
+
+}
diff --git a/core/modules/book/src/Form/BookAdminEditForm.php b/core/modules/book/src/Form/BookAdminEditForm.php
index 29fad4261403..9df174ded4ff 100644
--- a/core/modules/book/src/Form/BookAdminEditForm.php
+++ b/core/modules/book/src/Form/BookAdminEditForm.php
@@ -206,7 +206,7 @@ protected function bookAdminTableTree(array $tree, array &$form) {
     $delta = ($count < 30) ? 15 : intval($count / 2) + 1;
 
     $access = \Drupal::currentUser()->hasPermission('administer nodes');
-    $destination = drupal_get_destination();
+    $destination = $this->getDestinationArray();
 
     foreach ($tree as $data) {
       $nid = $data['link']['nid'];
diff --git a/core/modules/comment/src/CommentManager.php b/core/modules/comment/src/CommentManager.php
index 72b87a2e88ae..45705a210439 100644
--- a/core/modules/comment/src/CommentManager.php
+++ b/core/modules/comment/src/CommentManager.php
@@ -159,7 +159,7 @@ public function forbiddenMessage(EntityInterface $entity, $field_name) {
     }
 
     if ($this->authenticatedCanPostComments) {
-      // We cannot use drupal_get_destination() because these links
+      // We cannot use the redirect.destination service here because these links
       // sometimes appear on /node and taxonomy listing pages.
       if ($entity->get($field_name)->getFieldDefinition()->getSetting('form_location') == CommentItemInterface::FORM_SEPARATE_PAGE) {
         $comment_reply_parameters = [
diff --git a/core/modules/comment/src/Form/CommentAdminOverview.php b/core/modules/comment/src/Form/CommentAdminOverview.php
index f5243847e30f..9205de84de4c 100644
--- a/core/modules/comment/src/Form/CommentAdminOverview.php
+++ b/core/modules/comment/src/Form/CommentAdminOverview.php
@@ -167,7 +167,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $type = '
 
     // Build a table listing the appropriate comments.
     $options = array();
-    $destination = drupal_get_destination();
+    $destination = $this->getDestinationArray();
 
     $commented_entity_ids = array();
     $commented_entities = array();
diff --git a/core/modules/comment/src/Plugin/views/field/Link.php b/core/modules/comment/src/Plugin/views/field/Link.php
index 70c5c0ecf0ac..c2fc23d39038 100644
--- a/core/modules/comment/src/Plugin/views/field/Link.php
+++ b/core/modules/comment/src/Plugin/views/field/Link.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Url;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -24,6 +25,8 @@
  */
 class Link extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * Entity Manager service.
    *
diff --git a/core/modules/comment/src/Plugin/views/field/LinkApprove.php b/core/modules/comment/src/Plugin/views/field/LinkApprove.php
index b249a7459dc4..11e7812afce5 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkApprove.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkApprove.php
@@ -53,7 +53,7 @@ protected function renderLink($data, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = Url::fromRoute('comment.approve', ['comment' => $comment->id()]);
-    $this->options['alter']['query'] = drupal_get_destination() + array('token' => \Drupal::csrfToken()->get($this->options['alter']['url']->toString()));
+    $this->options['alter']['query'] = $this->getDestinationArray() + array('token' => \Drupal::csrfToken()->get($this->options['alter']['url']->toString()));
 
     return $text;
   }
diff --git a/core/modules/comment/src/Plugin/views/field/LinkDelete.php b/core/modules/comment/src/Plugin/views/field/LinkDelete.php
index b36c2235a62b..5ede03f472f6 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkDelete.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkDelete.php
@@ -44,7 +44,7 @@ protected function renderLink($data, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = $comment->urlInfo('delete-form');
-    $this->options['alter']['query'] = drupal_get_destination();
+    $this->options['alter']['query'] = $this->getDestinationArray();
 
     return $text;
   }
diff --git a/core/modules/comment/src/Plugin/views/field/LinkEdit.php b/core/modules/comment/src/Plugin/views/field/LinkEdit.php
index 316c272ed594..7ae06939a51d 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkEdit.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkEdit.php
@@ -60,7 +60,7 @@ protected function renderLink($data, ResultRow $values) {
     unset($this->options['alter']['fragment']);
 
     if (!empty($this->options['destination'])) {
-      $this->options['alter']['query'] = drupal_get_destination();
+      $this->options['alter']['query'] = $this->getDestinationArray();
     }
 
     $this->options['alter']['url'] = $comment->urlInfo('edit-form');
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 99c36eeaa40b..9ab0bfd6cae7 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -336,7 +336,7 @@ function content_translation_form_field_config_edit_form_alter(array &$form, For
   // Provide helpful pointers for administrators.
   if (\Drupal::currentUser()->hasPermission('administer content translation') &&  !$bundle_is_translatable) {
     $toggle_url = \Drupal::url('language.content_settings_page', array(), array(
-      'query' => drupal_get_destination(),
+      'query' => \Drupal::destination()->getAsArray(),
     ));
     $form['translatable']['#description'] = t('To configure translation for this field, <a href="@language-settings-url">enable language support</a> for this type.', array(
       '@language-settings-url' => $toggle_url,
diff --git a/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php b/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
index bb89a26b2be2..68929d1e2f05 100644
--- a/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
+++ b/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Url;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
@@ -24,6 +25,8 @@
  */
 class ContextualLinks extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -119,7 +122,7 @@ public function render(ResultRow $values) {
           'title' => $title,
         );
         if (!empty($this->options['destination'])) {
-          $links[$field]['query'] = drupal_get_destination();
+          $links[$field]['query'] = $this->getDestinationArray();
         }
       }
     }
diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
index 0c07e7fbe560..b26c225b2840 100644
--- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php
+++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
@@ -417,7 +417,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     }
 
     if ($destinations) {
-      $destination = drupal_get_destination();
+      $destination = $this->getDestinationArray();
       $destinations[] = $destination['destination'];
       $form_state->setRedirectUrl(FieldUI::getNextDestination($destinations, $form_state));
     }
diff --git a/core/modules/forum/src/Controller/ForumController.php b/core/modules/forum/src/Controller/ForumController.php
index 82165fff8e85..17c0454791e5 100644
--- a/core/modules/forum/src/Controller/ForumController.php
+++ b/core/modules/forum/src/Controller/ForumController.php
@@ -290,7 +290,7 @@ protected function buildActionLinks($vid, TermInterface $forum_term = NULL) {
           '#theme' => 'menu_local_action',
           '#link' => array(
             'title' => $this->t('Log in to post new content in the forum.'),
-            'url' => Url::fromRoute('user.login', [], ['query' => $this->getDestination()]),
+            'url' => Url::fromRoute('user.login', [], ['query' => $this->getDestinationArray()]),
           ),
         ];
       }
@@ -298,11 +298,4 @@ protected function buildActionLinks($vid, TermInterface $forum_term = NULL) {
     return $links;
   }
 
-  /**
-   * Wraps drupal_get_destination().
-   */
-  protected function getDestination() {
-    return drupal_get_destination();
-  }
-
 }
diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc
index 06807b66557c..41ce0b846f89 100644
--- a/core/modules/locale/locale.pages.inc
+++ b/core/modules/locale/locale.pages.inc
@@ -120,5 +120,5 @@ function template_preprocess_locale_translation_last_check(array &$variables) {
   $last = $variables['last'];
   $variables['last_checked'] = ($last != NULL);
   $variables['time'] = \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $last);
-  $variables['link'] = \Drupal::l(t('Check manually'), new Url('locale.check_translation', array(), array('query' => drupal_get_destination())));
+  $variables['link'] = \Drupal::l(t('Check manually'), new Url('locale.check_translation', array(), array('query' => \Drupal::destination()->getAsArray())));
 }
diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php
index fd38c02c7107..09f529aca456 100644
--- a/core/modules/menu_ui/src/MenuForm.php
+++ b/core/modules/menu_ui/src/MenuForm.php
@@ -383,7 +383,7 @@ protected function buildOverviewTreeForm($tree, $delta) {
         if ($edit_route) {
           $operations['edit']['url'] = $edit_route;
           // Bring the user back to the menu overview.
-          $operations['edit']['query'] = drupal_get_destination();
+          $operations['edit']['query'] = $this->getDestinationArray();
         }
         else {
           // Fall back to the standard edit link.
@@ -400,7 +400,7 @@ protected function buildOverviewTreeForm($tree, $delta) {
         }
         elseif ($delete_link = $link->getDeleteRoute()) {
           $operations['delete']['url'] = $delete_link;
-          $operations['delete']['query'] = drupal_get_destination();
+          $operations['delete']['query'] = $this->getDestinationArray();
           $operations['delete']['title'] = $this->t('Delete');
         }
         if ($link->isTranslatable()) {
diff --git a/core/modules/node/src/NodeListBuilder.php b/core/modules/node/src/NodeListBuilder.php
index 8d36deee749e..7acbfc9296f6 100644
--- a/core/modules/node/src/NodeListBuilder.php
+++ b/core/modules/node/src/NodeListBuilder.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Routing\RedirectDestinationInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -30,6 +31,13 @@ class NodeListBuilder extends EntityListBuilder {
    */
   protected $dateFormatter;
 
+  /**
+   * The redirect destination service.
+   *
+   * @var \Drupal\Core\Routing\RedirectDestinationInterface
+   */
+  protected $redirectDestination;
+
   /**
    * Constructs a new NodeListBuilder object.
    *
@@ -39,11 +47,14 @@ class NodeListBuilder extends EntityListBuilder {
    *   The entity storage class.
    * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
    *   The date formatter service.
+   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
+   *   The redirect destination service.
    */
-  public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, DateFormatter $date_formatter) {
+  public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, DateFormatter $date_formatter, RedirectDestinationInterface $redirect_destination) {
     parent::__construct($entity_type, $storage);
 
     $this->dateFormatter = $date_formatter;
+    $this->redirectDestination = $redirect_destination;
   }
 
   /**
@@ -53,7 +64,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
     return new static(
       $entity_type,
       $container->get('entity.manager')->getStorage($entity_type->id()),
-      $container->get('date.formatter')
+      $container->get('date.formatter'),
+      $container->get('redirect.destination')
     );
   }
 
@@ -128,7 +140,7 @@ public function buildRow(EntityInterface $entity) {
   protected function getDefaultOperations(EntityInterface $entity) {
     $operations = parent::getDefaultOperations($entity);
 
-    $destination = drupal_get_destination();
+    $destination = $this->redirectDestination->getAsArray();
     foreach ($operations as $key => $operation) {
       $operations[$key]['query'] = $destination;
     }
diff --git a/core/modules/node/src/Plugin/views/field/Link.php b/core/modules/node/src/Plugin/views/field/Link.php
index 54b51aec89db..a0d7ba727cae 100644
--- a/core/modules/node/src/Plugin/views/field/Link.php
+++ b/core/modules/node/src/Plugin/views/field/Link.php
@@ -8,6 +8,7 @@
 namespace Drupal\node\Plugin\views\field;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 
@@ -20,6 +21,8 @@
  */
 class Link extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/node/src/Plugin/views/field/LinkDelete.php b/core/modules/node/src/Plugin/views/field/LinkDelete.php
index 6bc515605b67..6dad5e05c39c 100644
--- a/core/modules/node/src/Plugin/views/field/LinkDelete.php
+++ b/core/modules/node/src/Plugin/views/field/LinkDelete.php
@@ -38,7 +38,7 @@ protected function renderLink($node, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = $node->urlInfo('delete-form');
-    $this->options['alter']['query'] = drupal_get_destination();
+    $this->options['alter']['query'] = $this->getDestinationArray();
 
     $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Delete');
     return $text;
diff --git a/core/modules/node/src/Plugin/views/field/LinkEdit.php b/core/modules/node/src/Plugin/views/field/LinkEdit.php
index eb8b9745db1d..6d466427708d 100644
--- a/core/modules/node/src/Plugin/views/field/LinkEdit.php
+++ b/core/modules/node/src/Plugin/views/field/LinkEdit.php
@@ -39,7 +39,7 @@ protected function renderLink($node, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = $node->urlInfo('edit-form');
-    $this->options['alter']['query'] = drupal_get_destination();
+    $this->options['alter']['query'] = $this->getDestinationArray();
 
     $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit');
     return $text;
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLink.php b/core/modules/node/src/Plugin/views/field/RevisionLink.php
index b510e50400f1..83701702c67f 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLink.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLink.php
@@ -66,7 +66,7 @@ protected function renderLink($data, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = $url;
-    $this->options['alter']['query'] = drupal_get_destination();
+    $this->options['alter']['query'] = $this->getDestinationArray();
 
     return !empty($this->options['text']) ? $this->options['text'] : $this->t('View');
   }
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php b/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
index 1d5a14b59bdd..c7519d0a1701 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
@@ -52,7 +52,7 @@ protected function renderLink($data, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid]);
-    $this->options['alter']['query'] = drupal_get_destination();
+    $this->options['alter']['query'] = $this->getDestinationArray();
 
     return !empty($this->options['text']) ? $this->options['text'] : $this->t('Delete');
   }
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php b/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
index 17db8a8deaa2..a5d1c97fff5f 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
@@ -52,7 +52,7 @@ protected function renderLink($data, ResultRow $values) {
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid]);
-    $this->options['alter']['query'] = drupal_get_destination();
+    $this->options['alter']['query'] = $this->getDestinationArray();
 
     return !empty($this->options['text']) ? $this->options['text'] : $this->t('Revert');
   }
diff --git a/core/modules/path/src/Controller/PathController.php b/core/modules/path/src/Controller/PathController.php
index 8756270c1865..cdb596de1eea 100644
--- a/core/modules/path/src/Controller/PathController.php
+++ b/core/modules/path/src/Controller/PathController.php
@@ -83,7 +83,7 @@ public function adminOverview(Request $request) {
     $header[] = $this->t('Operations');
 
     $rows = array();
-    $destination = drupal_get_destination();
+    $destination = $this->getDestinationArray();
     foreach ($this->aliasStorage->getAliasesForAdminListing($header, $keys) as $data) {
       $row = array();
       // @todo Should Path module store leading slashes? See
diff --git a/core/modules/path/src/Form/EditForm.php b/core/modules/path/src/Form/EditForm.php
index 18863d71aa8f..fc85a42e095a 100644
--- a/core/modules/path/src/Form/EditForm.php
+++ b/core/modules/path/src/Form/EditForm.php
@@ -58,7 +58,7 @@ public function deleteSubmit(array &$form, FormStateInterface $form_state) {
     ));
 
     if ($this->getRequest()->query->has('destination')) {
-      $url->setOption('query', drupal_get_destination());
+      $url->setOption('query', $this->getDestinationArray());
       $this->getRequest()->query->remove('destination');
     }
 
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index d57af75e3d67..459ea2970c58 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -313,7 +313,7 @@ function shortcut_preprocess_page(&$variables) {
       'link' => $link,
       'name' => $variables['title'],
     );
-    $query += drupal_get_destination();
+    $query += \Drupal::destination()->getAsArray();
 
     $shortcut_set = shortcut_current_displayed_set();
 
diff --git a/core/modules/system/src/Plugin/views/field/BulkForm.php b/core/modules/system/src/Plugin/views/field/BulkForm.php
index f4a25453fd29..b67bf8a349d7 100644
--- a/core/modules/system/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/system/src/Plugin/views/field/BulkForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\style\Table;
@@ -24,6 +25,8 @@
  */
 class BulkForm extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * The action storage.
    *
@@ -284,7 +287,7 @@ public function viewsFormSubmit(&$form, FormStateInterface $form_state) {
       $operation_definition = $action->getPluginDefinition();
       if (!empty($operation_definition['confirm_form_route_name'])) {
         $options = array(
-          'query' => drupal_get_destination(),
+          'query' => $this->getDestinationArray(),
         );
         $form_state->setRedirect($operation_definition['confirm_form_route_name'], array(), $options);
       }
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index d2bda7f33db7..88f9023d921f 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -729,7 +729,7 @@ function system_user_login(UserInterface $account) {
   $config = \Drupal::config('system.date');
   // If the user has a NULL time zone, notify them to set a time zone.
   if (!$account->getTimezone() && $config->get('timezone.user.configurable') && $config->get('timezone.user.warn')) {
-    drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => $account->url('edit-form', array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
+    drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => $account->url('edit-form', array('query' => \Drupal::destination()->getAsArray(), 'fragment' => 'edit-timezone')))));
   }
 }
 
diff --git a/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php b/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php
index 0b4c42a5e229..8d89b6eefca2 100644
--- a/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php
+++ b/core/modules/system/tests/modules/common_test/src/Controller/CommonTestController.php
@@ -89,9 +89,8 @@ public function jsAndCssQuerystring() {
    *   parameter.
    */
   public function destination() {
-    $destination = drupal_get_destination();
+    $destination = \Drupal::destination()->getAsArray();
     $output = "The destination: " . SafeMarkup::checkPlain($destination['destination']);
-
     return new Response($output);
   }
 
diff --git a/core/modules/taxonomy/src/Form/OverviewTerms.php b/core/modules/taxonomy/src/Form/OverviewTerms.php
index 9e7e3910daf8..eebbacc26a89 100644
--- a/core/modules/taxonomy/src/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/src/Form/OverviewTerms.php
@@ -200,7 +200,7 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
     }
 
     $errors = $form_state->getErrors();
-    $destination = drupal_get_destination();
+    $destination = $this->getDestinationArray();
     $row_position = 0;
     // Build the actual form.
     $form['terms'] = array(
diff --git a/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php b/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php
index 306c02cc8a2a..10f03373a802 100644
--- a/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php
+++ b/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy\Plugin\views\field;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Url;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -23,6 +24,8 @@
  */
 class LinkEdit extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -78,7 +81,7 @@ public function render(ResultRow $values) {
       ));
       if ($term->access('update')) {
         $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit');
-        return \Drupal::l($text, new Url('entity.taxonomy.edit_form', ['taxonomy_term' => $tid], array('query' => drupal_get_destination())));
+        return \Drupal::l($text, new Url('entity.taxonomy.edit_form', ['taxonomy_term' => $tid], array('query' => $this->getDestinationArray())));
       }
     }
   }
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 6f4403ddf10c..b8cb1c8bcbad 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -290,7 +290,7 @@ function update_storage_clear_submit($form, FormStateInterface $form_state) {
  * Returns a warning message when there is no data about available updates.
  */
 function _update_no_data() {
-  $destination = drupal_get_destination();
+  $destination = \Drupal::destination()->getAsArray();
   return t('No update information available. <a href="@run_cron">Run cron</a> or <a href="@check_manually">check manually</a>.', array(
     '@run_cron' => \Drupal::url('system.run_cron', [], ['query' => $destination]),
     '@check_manually' => \Drupal::url('update.manual_status', [], ['query' => $destination]),
@@ -590,7 +590,7 @@ function _update_project_status_sort($a, $b) {
  */
 function template_preprocess_update_last_check(&$variables) {
   $variables['time'] = \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $variables['last']);
-  $variables['link'] = \Drupal::l(t('Check manually'), new Url('update.manual_status', array(), array('query' => drupal_get_destination())));
+  $variables['link'] = \Drupal::l(t('Check manually'), new Url('update.manual_status', array(), array('query' => \Drupal::destination()->getAsArray())));
 }
 
 /**
diff --git a/core/modules/user/src/Plugin/Block/UserLoginBlock.php b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
index 64c4990ef6f5..3f28d3c331c0 100644
--- a/core/modules/user/src/Plugin/Block/UserLoginBlock.php
+++ b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\Block;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\UrlGeneratorTrait;
 use Drupal\Core\Url;
@@ -27,6 +28,7 @@
 class UserLoginBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
   use UrlGeneratorTrait;
+  use RedirectDestinationTrait;
 
   /**
    * The route match.
@@ -87,7 +89,7 @@ public function build() {
     unset($form['pass']['#description']);
     $form['name']['#size'] = 15;
     $form['pass']['#size'] = 15;
-    $form['#action'] = $this->url('<current>', [], ['query' => drupal_get_destination(), 'external' => FALSE]);
+    $form['#action'] = $this->url('<current>', [], ['query' => $this->getDestinationArray(), 'external' => FALSE]);
     // Build action links.
     $items = array();
     if (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) {
diff --git a/core/modules/user/src/Plugin/views/field/Link.php b/core/modules/user/src/Plugin/views/field/Link.php
index 0bca949238ab..78057cc94be8 100644
--- a/core/modules/user/src/Plugin/views/field/Link.php
+++ b/core/modules/user/src/Plugin/views/field/Link.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\field;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -24,6 +25,8 @@
  */
 class Link extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/user/src/Plugin/views/field/LinkCancel.php b/core/modules/user/src/Plugin/views/field/LinkCancel.php
index abdbec7c4277..b29c426a9a06 100644
--- a/core/modules/user/src/Plugin/views/field/LinkCancel.php
+++ b/core/modules/user/src/Plugin/views/field/LinkCancel.php
@@ -29,7 +29,7 @@ protected function renderLink(EntityInterface $entity, ResultRow $values) {
       $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Cancel account');
 
       $this->options['alter']['url'] = $entity->urlInfo('cancel-form');
-      $this->options['alter']['query'] = drupal_get_destination();
+      $this->options['alter']['query'] = $this->getDestinationArray();
 
       return $text;
     }
diff --git a/core/modules/user/src/Plugin/views/field/LinkEdit.php b/core/modules/user/src/Plugin/views/field/LinkEdit.php
index bb288631be92..23a4f5a4b984 100644
--- a/core/modules/user/src/Plugin/views/field/LinkEdit.php
+++ b/core/modules/user/src/Plugin/views/field/LinkEdit.php
@@ -28,7 +28,7 @@ protected function renderLink(EntityInterface $entity, ResultRow $values) {
 
       $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit');
 
-      $this->options['alter']['url'] = $entity->urlInfo('edit-form', ['query' => ['destination' => drupal_get_destination()]]);
+      $this->options['alter']['url'] = $entity->urlInfo('edit-form', ['query' => ['destination' => $this->getDestinationArray()]]);
 
       return $text;
     }
diff --git a/core/modules/user/src/UserListBuilder.php b/core/modules/user/src/UserListBuilder.php
index c60001621f0f..e6ae82d69d20 100644
--- a/core/modules/user/src/UserListBuilder.php
+++ b/core/modules/user/src/UserListBuilder.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Routing\RedirectDestinationInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -36,6 +37,13 @@ class UserListBuilder extends EntityListBuilder {
    */
   protected $dateFormatter;
 
+  /**
+   * The redirect destination service.
+   *
+   * @var \Drupal\Core\Routing\RedirectDestinationInterface
+   */
+  protected $redirectDestination;
+
   /**
    * Constructs a new UserListBuilder object.
    *
@@ -47,11 +55,14 @@ class UserListBuilder extends EntityListBuilder {
    *   The entity query factory.
    * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
    *   The date formatter service.
+   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
+   *   The redirect destination service.
    */
-  public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, QueryFactory $query_factory, DateFormatter $date_formatter) {
+  public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, QueryFactory $query_factory, DateFormatter $date_formatter,  RedirectDestinationInterface $redirect_destination) {
     parent::__construct($entity_type, $storage);
     $this->queryFactory = $query_factory;
     $this->dateFormatter = $date_formatter;
+    $this->redirectDestination = $redirect_destination;
   }
 
   /**
@@ -62,7 +73,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $entity_type,
       $container->get('entity.manager')->getStorage($entity_type->id()),
       $container->get('entity.query'),
-      $container->get('date.formatter')
+      $container->get('date.formatter'),
+      $container->get('redirect.destination')
     );
   }
 
@@ -152,7 +164,7 @@ public function buildRow(EntityInterface $entity) {
   public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
     if (isset($operations['edit'])) {
-      $destination = drupal_get_destination();
+      $destination = $this->redirectDestination->getAsArray();
       $operations['edit']['query'] = $destination;
     }
     return $operations;
diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php
index 928a56aba2a6..74469f397fc0 100644
--- a/core/modules/user/user.api.php
+++ b/core/modules/user/user.api.php
@@ -136,7 +136,7 @@ function hook_user_login($account) {
   $config = \Drupal::config('system.date');
   // If the user has a NULL time zone, notify them to set a time zone.
   if (!$account->getTimezone() && $config->get('timezone.user.configurable') && $config->get('timezone.user.warn')) {
-    drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => $account->url('edit-form', array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
+    drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => $account->url('edit-form', array('query' => \Drupal::destination()->getAsArray(), 'fragment' => 'edit-timezone')))));
   }
 }
 
diff --git a/core/modules/views/src/Controller/ViewAjaxController.php b/core/modules/views/src/Controller/ViewAjaxController.php
index 43e41e0c6354..bd5f95679f16 100644
--- a/core/modules/views/src/Controller/ViewAjaxController.php
+++ b/core/modules/views/src/Controller/ViewAjaxController.php
@@ -157,7 +157,7 @@ public function ajaxView(Request $request) {
         $request->query->replace($request_all + $query_all);
 
         // Overwrite the destination.
-        // @see drupal_get_destination()
+        // @see the redirect.destination service.
         $origin_destination = $path;
         $query = UrlHelper::buildQuery($request->query->all());
         if ($query != '') {
diff --git a/core/modules/views/src/Plugin/views/field/EntityOperations.php b/core/modules/views/src/Plugin/views/field/EntityOperations.php
index 3b9128c0ffcb..35fbfc3eaf18 100644
--- a/core/modules/views/src/Plugin/views/field/EntityOperations.php
+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -21,6 +22,8 @@
  */
 class EntityOperations extends FieldPluginBase {
 
+  use RedirectDestinationTrait;
+
   /**
    * The entity manager.
    *
@@ -102,7 +105,7 @@ public function render(ResultRow $values) {
         if (!isset($operation['query'])) {
           $operation['query'] = array();
         }
-        $operation['query'] += drupal_get_destination();
+        $operation['query'] += $this->getDestinationArray();
       }
     }
     $build = array(
diff --git a/core/modules/views/src/Plugin/views/field/Links.php b/core/modules/views/src/Plugin/views/field/Links.php
index 1953c569c634..93c20814c5e8 100644
--- a/core/modules/views/src/Plugin/views/field/Links.php
+++ b/core/modules/views/src/Plugin/views/field/Links.php
@@ -89,7 +89,7 @@ protected function getLinks() {
         'title' => $title,
       );
       if (!empty($this->options['destination'])) {
-        $links[$field]['query'] = drupal_get_destination();
+        $links[$field]['query'] = \Drupal::destination()->getAsArray();
       }
     }
 
diff --git a/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php b/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php
index 6f14c928eeb8..f93a16bb143e 100644
--- a/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php
+++ b/core/modules/views/tests/src/Unit/Controller/ViewAjaxControllerTest.php
@@ -334,12 +334,3 @@ protected function assertViewResultCommand(ViewAjaxResponse $response, $position
 
 }
 
-namespace {
-  // @todo Remove once drupal_get_destination is converted to autoloadable code.
-  if (!function_exists('drupal_static')) {
-    function &drupal_static($key) {
-      return $key;
-    }
-  }
-
-}
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/EntityOperationsUnitTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/EntityOperationsUnitTest.php
index e8eee20b2a74..c7c700265279 100644
--- a/core/modules/views/tests/src/Unit/Plugin/views/field/EntityOperationsUnitTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/EntityOperationsUnitTest.php
@@ -45,6 +45,13 @@ public function setUp() {
       'title' => $this->randomMachineName(),
     );
     $this->plugin = new EntityOperations($configuration, $plugin_id, $plugin_definition, $this->entityManager);
+
+    $redirect_service = $this->getMock('Drupal\Core\Routing\RedirectDestinationInterface');
+    $redirect_service->expects($this->any())
+      ->method('getAsArray')
+      ->willReturn(['destination' => 'foobar']);
+    $this->plugin->setRedirectDestination($redirect_service);
+
     $view = $this->getMockBuilder('\Drupal\views\ViewExecutable')
       ->disableOriginalConstructor()
       ->getMock();
@@ -108,7 +115,7 @@ public function testRenderWithDestination() {
       '#type' => 'operations',
       '#links' => $operations
     );
-    $expected_build['#links']['foo']['query'] = drupal_get_destination();
+    $expected_build['#links']['foo']['query'] = ['destination' => 'foobar'];
     $build = $this->plugin->render($result);
     $this->assertSame($expected_build, $build);
   }
@@ -156,15 +163,3 @@ public function testRenderWithoutDestination() {
 }
 
 }
-
-namespace {
-
-if (!function_exists('drupal_get_destination')) {
-  function drupal_get_destination() {
-    return array(
-      'destination' => 'foobar',
-    );
-  }
-}
-
-}
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/CustomPageExceptionHtmlSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/CustomPageExceptionHtmlSubscriberTest.php
index 5b73c85f819b..ffb2a2180d29 100644
--- a/core/tests/Drupal/Tests/Core/EventSubscriber/CustomPageExceptionHtmlSubscriberTest.php
+++ b/core/tests/Drupal/Tests/Core/EventSubscriber/CustomPageExceptionHtmlSubscriberTest.php
@@ -64,6 +64,13 @@ class CustomPageExceptionHtmlSubscriberTest extends UnitTestCase {
    */
   protected $customPageSubscriber;
 
+  /**
+   * The mocked redirect.destination service.
+   *
+   * @var \Drupal\Core\Routing\RedirectDestinationInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $redirectDestination;
+
   /**
    * {@inheritdoc}
    */
@@ -73,7 +80,13 @@ protected function setUp() {
     $this->aliasManager = $this->getMock('Drupal\Core\Path\AliasManagerInterface');
     $this->kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
     $this->logger = $this->getMock('Psr\Log\LoggerInterface');
-    $this->customPageSubscriber = new TestCustomPageExceptionHtmlSubscriber($this->configFactory, $this->aliasManager, $this->kernel, $this->logger);
+    $this->redirectDestination = $this->getMock('\Drupal\Core\Routing\RedirectDestinationInterface');
+
+    $this->redirectDestination->expects($this->any())
+      ->method('getAsArray')
+      ->willReturn(['destination' => 'test']);
+
+    $this->customPageSubscriber = new CustomPageExceptionHtmlSubscriber($this->configFactory, $this->aliasManager, $this->kernel, $this->logger, $this->redirectDestination);
 
     // You can't create an exception in PHP without throwing it. Store the
     // current error_log, and disable it temporarily.
@@ -139,13 +152,3 @@ public function testHandleWithGetRequest() {
 
 }
 
-class TestCustomPageExceptionHtmlSubscriber extends CustomPageExceptionHtmlSubscriber {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function drupalGetDestination() {
-    return ['destination' => 'test'];
-  }
-
-}
-- 
GitLab