From 81658d5c8793cf9676224d5b680e28fb45e78866 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Wed, 15 Jul 2015 15:03:31 +0100
Subject: [PATCH] Issue #2512132 by Wim Leers, effulgentsia, Fabianx: Make CSRF
 links cacheable

---
 core/core.services.yml                        |  5 ++
 core/lib/Drupal.php                           | 24 +++----
 .../Drupal/Core/Access/RouteProcessorCsrf.php | 45 ++++++++++--
 .../Cache/Context/SessionCacheContext.php     | 31 +++++++++
 core/lib/Drupal/Core/GeneratedLink.php        |  4 +-
 core/lib/Drupal/Core/GeneratedUrl.php         |  6 +-
 core/lib/Drupal/Core/Link.php                 | 12 ++--
 .../OutboundPathProcessorInterface.php        |  8 +--
 .../Core/PathProcessor/PathProcessorAlias.php |  4 +-
 .../Core/PathProcessor/PathProcessorFront.php |  4 +-
 .../PathProcessor/PathProcessorManager.php    |  6 +-
 .../Drupal/Core/Render/BubbleableMetadata.php | 21 ++++++
 core/lib/Drupal/Core/Render/Element/Link.php  |  3 +-
 .../OutboundRouteProcessorInterface.php       |  8 +--
 .../RouteProcessor/RouteProcessorCurrent.php  |  7 +-
 .../RouteProcessor/RouteProcessorManager.php  |  6 +-
 .../lib/Drupal/Core/Routing/NullGenerator.php |  6 +-
 core/lib/Drupal/Core/Routing/UrlGenerator.php | 38 +++++------
 .../Core/Routing/UrlGeneratorInterface.php    | 20 +++---
 .../Drupal/Core/Template/TwigExtension.php    |  4 +-
 core/lib/Drupal/Core/Url.php                  | 14 ++--
 .../lib/Drupal/Core/Utility/LinkGenerator.php | 14 ++--
 .../Core/Utility/LinkGeneratorInterface.php   | 20 +++---
 .../Core/Utility/UnroutedUrlAssembler.php     | 18 ++---
 .../Utility/UnroutedUrlAssemblerInterface.php | 10 +--
 .../help_test/src/SupernovaGenerator.php      |  4 +-
 .../src/HttpKernel/PathProcessorLanguage.php  |  6 +-
 .../LanguageNegotiationSession.php            |  8 +--
 .../LanguageNegotiationUrl.php                | 12 ++--
 .../src/Unit/LanguageNegotiationUrlTest.php   | 10 +--
 ...enuLinkContentCacheabilityBubblingTest.php | 26 +++----
 .../system/src/Tests/Common/UrlTest.php       | 19 +++---
 .../Tests/RouteProcessor/RouteNoneTest.php    |  4 +-
 .../RouteProcessorCurrentIntegrationTest.php  |  6 +-
 .../url_alter_test/src/PathProcessorTest.php  |  8 +--
 .../Core/Access/RouteProcessorCsrfTest.php    | 68 ++++++++++---------
 .../PathProcessor/PathProcessorAliasTest.php  |  8 +--
 .../RouteProcessorManagerTest.php             |  8 +--
 .../Tests/Core/Routing/UrlGeneratorTest.php   | 48 ++++++-------
 core/tests/Drupal/Tests/Core/UrlTest.php      |  6 +-
 .../Tests/Core/Utility/LinkGeneratorTest.php  |  8 +--
 .../Core/Utility/UnroutedUrlAssemblerTest.php | 10 +--
 42 files changed, 345 insertions(+), 252 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php

diff --git a/core/core.services.yml b/core/core.services.yml
index bf21661d8bce..f9d7cc8aaca9 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -24,6 +24,11 @@ services:
     arguments: ['@request_stack']
     tags:
       - { name: cache.context }
+  cache_context.session:
+    class: Drupal\Core\Cache\Context\SessionCacheContext
+    arguments: ['@request_stack']
+    tags:
+      - { name: cache.context}
   cache_context.request_format:
     class: Drupal\Core\Cache\Context\RequestFormatCacheContext
     arguments: ['@request_stack']
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 0c4305bfaa69..e15a92010a57 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -504,22 +504,22 @@ public static function urlGenerator() {
    *   (optional) An associative array of parameter names and values.
    * @param array $options
    *   (optional) An associative array of additional options.
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedUrl
    *   A string containing a URL to the given path.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedUrl object is
-   *   returned, containing the generated URL plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is
+   *   returned, containing the generated URL plus bubbleable metadata.
    *
    * @see \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute()
    * @see \Drupal\Core\Url
    * @see \Drupal\Core\Url::fromRoute()
    * @see \Drupal\Core\Url::fromUri()
    */
-  public static function url($route_name, $route_parameters = array(), $options = array(), $collect_cacheability_metadata = FALSE) {
-    return static::getContainer()->get('url_generator')->generateFromRoute($route_name, $route_parameters, $options, $collect_cacheability_metadata);
+  public static function url($route_name, $route_parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE) {
+    return static::getContainer()->get('url_generator')->generateFromRoute($route_name, $route_parameters, $options, $collect_bubbleable_metadata);
   }
 
   /**
@@ -542,20 +542,20 @@ public static function linkGenerator() {
    *   The link text for the anchor tag.
    * @param \Drupal\Core\Url $url
    *   The URL object used for the link.
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedLink
    *   An HTML string containing a link to the given route and parameters.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedLink object is
-   *   returned, containing the generated link plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
+   *   returned, containing the generated link plus bubbleable metadata.
    *
    * @see \Drupal\Core\Utility\LinkGeneratorInterface::generate()
    * @see \Drupal\Core\Url
    */
-  public static function l($text, Url $url, $collect_cacheability_metadata = FALSE) {
-    return static::getContainer()->get('link_generator')->generate($text, $url, $collect_cacheability_metadata);
+  public static function l($text, Url $url, $collect_bubbleable_metadata = FALSE) {
+    return static::getContainer()->get('link_generator')->generate($text, $url, $collect_bubbleable_metadata);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php b/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php
index 5399d9e09e78..bd3a5527891d 100644
--- a/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php
+++ b/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Access;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface;
 use Symfony\Component\Routing\Route;
 
@@ -36,7 +36,7 @@ function __construct(CsrfTokenGenerator $csrf_token) {
   /**
    * {@inheritdoc}
    */
-  public function processOutbound($route_name, Route $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
     if ($route->hasRequirement('_csrf_token')) {
       $path = ltrim($route->getPath(), '/');
       // Replace the path parameters with values from the parameters array.
@@ -45,13 +45,44 @@ public function processOutbound($route_name, Route $route, array &$parameters, C
       }
       // Adding this to the parameters means it will get merged into the query
       // string when the route is compiled.
-      $parameters['token'] = $this->csrfToken->get($path);
-      if ($cacheable_metadata) {
-        // Tokens are per user and per session, so not cacheable.
-        // @todo Improve in https://www.drupal.org/node/2351015.
-        $cacheable_metadata->setCacheMaxAge(0);
+      if (!$bubbleable_metadata) {
+        $parameters['token'] = $this->csrfToken->get($path);
+      }
+      else {
+        // Generate a placeholder and a render array to replace it.
+        $placeholder = hash('sha1', $path);
+        $placeholder_render_array = [
+          '#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
+        ];
+
+        // Instead of setting an actual CSRF token as the query string, we set
+        // the placeholder, which will be replaced at the very last moment. This
+        // ensures links with CSRF tokens don't break cacheability.
+        $parameters['token'] = $placeholder;
+        $bubbleable_metadata->addAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]);
       }
     }
   }
 
+  /**
+   * #lazy_builder callback; gets a CSRF token for the given path.
+   *
+   * @param string $path
+   *   The path to get a CSRF token for.
+   *
+   * @return array
+   *   A renderable array representing the CSRF token.
+   */
+  public function renderPlaceholderCsrfToken($path) {
+    return [
+      '#markup' => $this->csrfToken->get($path),
+      // Tokens are per session.
+      '#cache' => [
+        'contexts' => [
+          'session',
+        ],
+      ],
+    ];
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php b/core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php
new file mode 100644
index 000000000000..474032e35121
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\Context\SessionCacheContext.
+ */
+
+namespace Drupal\Core\Cache\Context;
+
+/**
+ * Defines the SessionCacheContext service, for "per session" caching.
+ *
+ * Cache context ID: 'session'.
+ */
+class SessionCacheContext extends RequestStackCacheContextBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getLabel() {
+    return t('Session');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContext() {
+    return $this->requestStack->getCurrentRequest()->getSession()->getId();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/GeneratedLink.php b/core/lib/Drupal/Core/GeneratedLink.php
index 7d5b0c316572..eb35bc6202f2 100644
--- a/core/lib/Drupal/Core/GeneratedLink.php
+++ b/core/lib/Drupal/Core/GeneratedLink.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 
 /**
  * Used to return generated links, along with associated cacheability metadata.
@@ -15,7 +15,7 @@
  * Note: not to be confused with \Drupal\Core\Link, which is for passing around
  *   ungenerated links (typically link text + route name + route parameters).
  */
-class GeneratedLink extends CacheableMetadata {
+class GeneratedLink extends BubbleableMetadata {
 
   /**
    * The HTML string value containing a link.
diff --git a/core/lib/Drupal/Core/GeneratedUrl.php b/core/lib/Drupal/Core/GeneratedUrl.php
index 7c5574722bf4..68df6e1c6895 100644
--- a/core/lib/Drupal/Core/GeneratedUrl.php
+++ b/core/lib/Drupal/Core/GeneratedUrl.php
@@ -7,15 +7,15 @@
 
 namespace Drupal\Core;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 
 /**
- * Used to return generated URLs, along with associated cacheability metadata.
+ * Used to return generated URLs, along with associated bubbleable metadata.
  *
  * Note: not to be confused with \Drupal\Core\Url, which is for passing around
  *   ungenerated URLs (typically route name + route parameters).
  */
-class GeneratedUrl extends CacheableMetadata {
+class GeneratedUrl extends BubbleableMetadata {
 
   /**
    * The string value of the URL.
diff --git a/core/lib/Drupal/Core/Link.php b/core/lib/Drupal/Core/Link.php
index 73bbcf55a45e..05869a24ef58 100644
--- a/core/lib/Drupal/Core/Link.php
+++ b/core/lib/Drupal/Core/Link.php
@@ -122,17 +122,17 @@ public function setUrl(Url $url) {
   /**
    * Generates the HTML for this Link object.
    *
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated link and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedLink
    *   The link HTML markup.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedLink object is
-   *   returned, containing the generated link plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
+   *   returned, containing the generated link plus bubbleable metadata.
    */
-  public function toString($collect_cacheability_metadata = FALSE) {
-    return $this->getLinkGenerator()->generateFromLink($this, $collect_cacheability_metadata);
+  public function toString($collect_bubbleable_metadata = FALSE) {
+    return $this->getLinkGenerator()->generateFromLink($this, $collect_bubbleable_metadata);
   }
 
 }
diff --git a/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php b/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php
index 774f385b0fe3..8826a93c510f 100644
--- a/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php
+++ b/core/lib/Drupal/Core/PathProcessor/OutboundPathProcessorInterface.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\PathProcessor;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -25,12 +25,12 @@ interface OutboundPathProcessorInterface {
    *   generateFromPath() method.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The HttpRequest object representing the current request.
-   * @param \Drupal\Core\Cache\CacheableMetadata $cacheable_metadata
-   *   (optional) Object to collect path processors' cacheability.
+   * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
+   *   (optional) Object to collect path processors' bubbleable metadata.
    *
    * @return
    *   The processed path.
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL);
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL);
 
 }
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php
index 206e56635689..d7bd41615f18 100644
--- a/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorAlias.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Core\PathProcessor;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Path\AliasManagerInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -44,7 +44,7 @@ public function processInbound($path, Request $request) {
   /**
    * Implements Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound().
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     if (empty($options['alias'])) {
       $langcode = isset($options['language']) ? $options['language']->getId() : NULL;
       $path = $this->aliasManager->getAliasByPath($path, $langcode);
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php
index bd1d8c1bb460..161661ba29b7 100644
--- a/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorFront.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Core\PathProcessor;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -48,7 +48,7 @@ public function processInbound($path, Request $request) {
   /**
    * Implements Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound().
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     // The special path '<front>' links to the default front page.
     if ($path === '/<front>') {
       $path = '/';
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
index 9974bc94861c..bd623273b06a 100644
--- a/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\PathProcessor;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -108,10 +108,10 @@ public function addOutbound(OutboundPathProcessorInterface $processor, $priority
   /**
    * Implements Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound().
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     $processors = $this->getOutbound();
     foreach ($processors as $processor) {
-      $path = $processor->processOutbound($path, $options, $request, $cacheable_metadata);
+      $path = $processor->processOutbound($path, $options, $request, $bubbleable_metadata);
     }
     return $path;
   }
diff --git a/core/lib/Drupal/Core/Render/BubbleableMetadata.php b/core/lib/Drupal/Core/Render/BubbleableMetadata.php
index dd53b73a90b4..81e7237ec555 100644
--- a/core/lib/Drupal/Core/Render/BubbleableMetadata.php
+++ b/core/lib/Drupal/Core/Render/BubbleableMetadata.php
@@ -73,6 +73,27 @@ public static function createFromRenderArray(array $build) {
     return $meta;
   }
 
+  /**
+   * Creates a bubbleable metadata object from a depended object.
+   *
+   * @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $object
+   *   The object whose cacheability metadata to retrieve. If it implements
+   *   CacheableDependencyInterface, its cacheability metadata will be used,
+   *   otherwise, the passed in object must be assumed to be uncacheable, so
+   *   max-age 0 is set.
+   *
+   * @return static
+   */
+  public static function createFromObject($object) {
+    $meta = parent::createFromObject($object);
+
+    if ($object instanceof AttachmentsInterface) {
+      $meta->attachments = $object->getAttachments();
+    }
+
+    return $meta;
+  }
+
   /**
    * Merges two attachments arrays (which live under the '#attached' key).
    *
diff --git a/core/lib/Drupal/Core/Render/Element/Link.php b/core/lib/Drupal/Core/Render/Element/Link.php
index 29734583d2ae..bec234100d97 100644
--- a/core/lib/Drupal/Core/Render/Element/Link.php
+++ b/core/lib/Drupal/Core/Render/Element/Link.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Html as HtmlUtility;
 use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Url as CoreUrl;
 
 /**
@@ -83,7 +84,7 @@ public static function preRenderLink($element) {
       $link_generator = \Drupal::service('link_generator');
       $generated_link = $link_generator->generate($element['#title'], $element['#url']->setOptions($options), TRUE);
       $element['#markup'] = $generated_link->getGeneratedLink();
-      $generated_link->merge(CacheableMetadata::createFromRenderArray($element))
+      $generated_link->merge(BubbleableMetadata::createFromRenderArray($element))
         ->applyTo($element);
     }
     return $element;
diff --git a/core/lib/Drupal/Core/RouteProcessor/OutboundRouteProcessorInterface.php b/core/lib/Drupal/Core/RouteProcessor/OutboundRouteProcessorInterface.php
index c3349ea05c19..b76ac4e38b05 100644
--- a/core/lib/Drupal/Core/RouteProcessor/OutboundRouteProcessorInterface.php
+++ b/core/lib/Drupal/Core/RouteProcessor/OutboundRouteProcessorInterface.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\RouteProcessor;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -25,12 +25,12 @@ interface OutboundRouteProcessorInterface {
    * @param array $parameters
    *   An array of parameters to be passed to the route compiler. Passed by
    *   reference.
-   * @param \Drupal\Core\Cache\CacheableMetadata $cacheable_metadata
-   *   (optional) Object to collect route processors' cacheability.
+   * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
+   *   (optional) Object to collect route processors' bubbleable metadata.
    *
    * @return
    *   The processed path.
    */
-  public function processOutbound($route_name, Route $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL);
+  public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL);
 
 }
diff --git a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorCurrent.php b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorCurrent.php
index 4d5784390117..0dbfcaa771e5 100644
--- a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorCurrent.php
+++ b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorCurrent.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\RouteProcessor;
 
 use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\Routing\Route;
 
@@ -36,7 +37,7 @@ public function __construct(RouteMatchInterface $route_match) {
   /**
    * {@inheritdoc}
    */
-  public function processOutbound($route_name, Route $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
     if ($route_name === '<current>') {
       if ($current_route = $this->routeMatch->getRouteObject()) {
         $requirements = $current_route->getRequirements();
@@ -52,8 +53,8 @@ public function processOutbound($route_name, Route $route, array &$parameters, C
         $route->setOptions($current_route->getOptions());
         $route->setDefaults($current_route->getDefaults());
         $parameters = array_merge($parameters, $this->routeMatch->getRawParameters()->all());
-        if ($cacheable_metadata) {
-          $cacheable_metadata->addCacheContexts(['route']);
+        if ($bubbleable_metadata) {
+          $bubbleable_metadata->addCacheContexts(['route']);
         }
       }
       else {
diff --git a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php
index c19b17740f6f..430af35effdd 100644
--- a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php
+++ b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\RouteProcessor;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -51,10 +51,10 @@ public function addOutbound(OutboundRouteProcessorInterface $processor, $priorit
   /**
    * {@inheritdoc}
    */
-  public function processOutbound($route_name, Route $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
     $processors = $this->getOutbound();
     foreach ($processors as $processor) {
-      $processor->processOutbound($route_name, $route, $parameters, $cacheable_metadata);
+      $processor->processOutbound($route_name, $route, $parameters, $bubbleable_metadata);
     }
   }
 
diff --git a/core/lib/Drupal/Core/Routing/NullGenerator.php b/core/lib/Drupal/Core/Routing/NullGenerator.php
index e095b5cc1c3b..29957f8b712f 100644
--- a/core/lib/Drupal/Core/Routing/NullGenerator.php
+++ b/core/lib/Drupal/Core/Routing/NullGenerator.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\Routing\RequestContext as SymfonyRequestContext;
 use Symfony\Component\Routing\Exception\RouteNotFoundException;
@@ -51,7 +51,7 @@ protected function getRoute($name) {
   /**
    * {@inheritdoc}
    */
-  protected function processRoute($name, Route $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL) {
+  protected function processRoute($name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
   }
 
   /**
@@ -76,7 +76,7 @@ public function getContext() {
   /**
    * Overrides Drupal\Core\Routing\UrlGenerator::processPath().
    */
-  protected function processPath($path, &$options = array(), CacheableMetadata $cacheable_metadata = NULL) {
+  protected function processPath($path, &$options = array(), BubbleableMetadata $bubbleable_metadata = NULL) {
     return $path;
   }
 }
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index bd3c1a088989..53c3098c7100 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Core\Routing;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\GeneratedUrl;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\Routing\RequestContext as SymfonyRequestContext;
 use Symfony\Component\Routing\Route as SymfonyRoute;
@@ -277,8 +277,8 @@ public function generate($name, $parameters = array(), $absolute = FALSE) {
   /**
    * {@inheritdoc}
    */
-  public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_cacheability_metadata = FALSE) {
-    $generated_url = $collect_cacheability_metadata ? new GeneratedUrl() : NULL;
+  public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE) {
+    $generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL;
 
     $options += array('prefix' => '');
     $route = $this->getRoute($name);
@@ -321,7 +321,7 @@ public function generateFromRoute($name, $parameters = array(), $options = array
       }
 
       $url = $base_url . $path . $fragment;
-      return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($url) : $url;
+      return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
     }
 
     $base_url = $this->context->getBaseUrl();
@@ -330,11 +330,11 @@ public function generateFromRoute($name, $parameters = array(), $options = array
     if (!$absolute || !$host = $this->context->getHost()) {
 
       if ($route->getOption('_only_fragment')) {
-        return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($fragment) : $fragment;
+        return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($fragment) : $fragment;
       }
 
       $url = $base_url . $path . $fragment;
-      return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($url) : $url;
+      return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
     }
 
     // Prepare an absolute URL by getting the correct scheme, host and port from
@@ -355,19 +355,19 @@ public function generateFromRoute($name, $parameters = array(), $options = array
     } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
       $port = ':' . $this->context->getHttpsPort();
     }
-    if ($collect_cacheability_metadata) {
+    if ($collect_bubbleable_metadata) {
       $generated_url->addCacheContexts(['url.site']);
     }
     $url = $scheme . '://' . $host . $port . $base_url . $path . $fragment;
-    return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($url) : $url;
+    return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
 
   }
 
   /**
    * {@inheritdoc}
    */
-  public function generateFromPath($path = NULL, $options = array(), $collect_cacheability_metadata = FALSE) {
-    $generated_url = $collect_cacheability_metadata ? new GeneratedUrl() : NULL;
+  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE) {
+    $generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL;
 
     $request = $this->requestStack->getCurrentRequest();
     $current_base_path = $request->getBasePath() . '/';
@@ -432,7 +432,7 @@ public function generateFromPath($path = NULL, $options = array(), $collect_cach
       }
       // Reassemble.
       $url = $path . $options['fragment'];
-      return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($url) : $url;
+      return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
     }
     else {
       $path = ltrim($this->processPath('/' . $path, $options, $generated_url), '/');
@@ -463,20 +463,20 @@ public function generateFromPath($path = NULL, $options = array(), $collect_cach
     $base = $options['absolute'] ? $options['base_url'] : $current_base_path;
     $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
 
-    if ($options['absolute'] && $collect_cacheability_metadata) {
+    if ($options['absolute'] && $collect_bubbleable_metadata) {
       $generated_url->addCacheContexts(['url.site']);
     }
 
     $path = str_replace('%2F', '/', rawurlencode($prefix . $path));
     $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : '';
     $url = $base . $options['script'] . $path . $query . $options['fragment'];
-    return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($url) : $url;
+    return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
   }
 
   /**
    * Passes the path to a processor manager to allow alterations.
    */
-  protected function processPath($path, &$options = array(), CacheableMetadata $cacheable_metadata = NULL) {
+  protected function processPath($path, &$options = array(), BubbleableMetadata $bubbleable_metadata = NULL) {
     // Router-based paths may have a querystring on them.
     if ($query_pos = strpos($path, '?')) {
       // We don't need to do a strict check here because position 0 would mean we
@@ -488,7 +488,7 @@ protected function processPath($path, &$options = array(), CacheableMetadata $ca
       $actual_path = $path;
       $query_string = '';
     }
-    $path = $this->pathProcessor->processOutbound($actual_path === '/' ? $actual_path : rtrim($actual_path, '/'), $options, $this->requestStack->getCurrentRequest(), $cacheable_metadata);
+    $path = $this->pathProcessor->processOutbound($actual_path === '/' ? $actual_path : rtrim($actual_path, '/'), $options, $this->requestStack->getCurrentRequest(), $bubbleable_metadata);
     $path .= $query_string;
     return $path;
   }
@@ -502,11 +502,11 @@ protected function processPath($path, &$options = array(), CacheableMetadata $ca
    *   The route object to process.
    * @param array $parameters
    *   An array of parameters to be passed to the route compiler.
-   * @param \Drupal\Core\Cache\CacheableMetadata $cacheable_metadata
-   *   (optional) Object to collect route processors' cacheability.
+   * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
+   *   (optional) Object to collect route processors' bubbleable metadata.
    */
-  protected function processRoute($name, SymfonyRoute $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL) {
-    $this->routeProcessor->processOutbound($name, $route, $parameters, $cacheable_metadata);
+  protected function processRoute($name, SymfonyRoute $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
+    $this->routeProcessor->processOutbound($name, $route, $parameters, $bubbleable_metadata);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php b/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
index 551171b44421..f75940fb6ce2 100644
--- a/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
+++ b/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
@@ -70,14 +70,14 @@ interface UrlGeneratorInterface extends VersatileGeneratorInterface {
    *     set if _url() is invoked by Drupal\Core\Entity\Entity::uri().
    *   - 'entity': The entity object (such as a node) for which the URL is being
    *     generated. Only set if _url() is invoked by Drupal\Core\Entity\Entity::uri().
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedUrl
    *   A string containing a URL to the given path.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedUrl object is
-   *   returned, containing the generated URL plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is
+   *   returned, containing the generated URL plus bubbleable metadata.
    *
    * @throws \Drupal\Core\Routing\GeneratorNotInitializedException.
    *
@@ -92,7 +92,7 @@ interface UrlGeneratorInterface extends VersatileGeneratorInterface {
    * @see \Drupal\Core\Url
    * @see \Drupal\Core\GeneratedUrl
    */
-  public function generateFromPath($path = NULL, $options = array(), $collect_cacheability_metadata = FALSE);
+  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE);
 
   /**
    * Gets the internal path (system path) of a route.
@@ -142,14 +142,14 @@ public function getPathFromRoute($name, $parameters = array());
    *     modify the base URL when a language dependent URL requires so.
    *   - 'prefix': Only used internally, to modify the path when a language
    *     dependent URL requires so.
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedUrl
    *   The generated URL for the given route.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedUrl object is
-   *   returned, containing the generated URL plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is
+   *   returned, containing the generated URL plus bubbleable metadata.
    *
    * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
    *   Thrown when the named route does not exist.
@@ -159,6 +159,6 @@ public function getPathFromRoute($name, $parameters = array());
    *   Thrown when a parameter value for a placeholder is not correct because it
    *   does not match the requirement.
    */
-  public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_cacheability_metadata = FALSE);
+  public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE);
 
 }
diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php
index b3bc4253269e..52a0b59b8f15 100644
--- a/core/lib/Drupal/Core/Template/TwigExtension.php
+++ b/core/lib/Drupal/Core/Template/TwigExtension.php
@@ -222,7 +222,7 @@ public function getUrl($name, $parameters = array(), $options = array()) {
     $options['absolute'] = TRUE;
     $generated_url = $this->urlGenerator->generateFromRoute($name, $parameters, $options, TRUE);
 
-    // Return as render array, so we can bubble the cacheability metadata.
+    // Return as render array, so we can bubble the bubbleable metadata.
     $build = ['#markup' => $generated_url->getGeneratedUrl()];
     $generated_url->applyTo($build);
     return $build;
@@ -247,7 +247,7 @@ public function getUrlFromPath($path, $options = array()) {
     $options['absolute'] = TRUE;
     $generated_url = $this->urlGenerator->generateFromPath($path, $options, TRUE);
 
-    // Return as render array, so we can bubble the cacheability metadata.
+    // Return as render array, so we can bubble the bubbleable metadata.
     $build = ['#markup' => $generated_url->getGeneratedUrl()];
     $generated_url->applyTo($build);
     return $build;
diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index 33895a5f2e03..e34962700027 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -732,21 +732,21 @@ public function setAbsolute($absolute = TRUE) {
    * http://example.com/node/1 depending on the options array, plus any
    * specified query string or fragment.
    *
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedUrl
    *   A string URL.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedUrl object is
-   *   returned, containing the generated URL plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is
+   *   returned, containing the generated URL plus bubbleable metadata.
    */
-  public function toString($collect_cacheability_metadata = FALSE) {
+  public function toString($collect_bubbleable_metadata = FALSE) {
     if ($this->unrouted) {
-      return $this->unroutedUrlAssembler()->assemble($this->getUri(), $this->getOptions(), $collect_cacheability_metadata);
+      return $this->unroutedUrlAssembler()->assemble($this->getUri(), $this->getOptions(), $collect_bubbleable_metadata);
     }
 
-    return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getOptions(), $collect_cacheability_metadata);
+    return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getOptions(), $collect_bubbleable_metadata);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php
index 1a9e22fbf426..1f6e1f904783 100644
--- a/core/lib/Drupal/Core/Utility/LinkGenerator.php
+++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php
@@ -63,8 +63,8 @@ public function __construct(UrlGeneratorInterface $url_generator, ModuleHandlerI
   /**
    * {@inheritdoc}
    */
-  public function generateFromLink(Link $link, $collect_cacheability_metadata = FALSE) {
-    return $this->generate($link->getText(), $link->getUrl(), $collect_cacheability_metadata);
+  public function generateFromLink(Link $link, $collect_bubbleable_metadata = FALSE) {
+    return $this->generate($link->getText(), $link->getUrl(), $collect_bubbleable_metadata);
   }
 
   /**
@@ -79,7 +79,7 @@ public function generateFromLink(Link $link, $collect_cacheability_metadata = FA
    *
    * @see system_page_attachments()
    */
-  public function generate($text, Url $url, $collect_cacheability_metadata = FALSE) {
+  public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE) {
     // Performance: avoid Url::toString() needing to retrieve the URL generator
     // service from the container.
     $url->setUrlGenerator($this->urlGenerator);
@@ -141,11 +141,11 @@ public function generate($text, Url $url, $collect_cacheability_metadata = FALSE
     unset($variables['options']['attributes']);
     $url->setOptions($variables['options']);
 
-    if (!$collect_cacheability_metadata) {
-      $url_string = $url->toString($collect_cacheability_metadata);
+    if (!$collect_bubbleable_metadata) {
+      $url_string = $url->toString($collect_bubbleable_metadata);
     }
     else {
-      $generated_url = $url->toString($collect_cacheability_metadata);
+      $generated_url = $url->toString($collect_bubbleable_metadata);
       $url_string = $generated_url->getGeneratedUrl();
       $generated_link = GeneratedLink::createFromObject($generated_url);
     }
@@ -155,7 +155,7 @@ public function generate($text, Url $url, $collect_cacheability_metadata = FALSE
 
     $result = SafeMarkup::format('<a@attributes>@text</a>', array('@attributes' => new Attribute($attributes), '@text' => $variables['text']));
 
-    return $collect_cacheability_metadata ? $generated_link->setGeneratedLink($result) : $result;
+    return $collect_bubbleable_metadata ? $generated_link->setGeneratedLink($result) : $result;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php
index b65526a00017..733c449be341 100644
--- a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php
+++ b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php
@@ -60,14 +60,14 @@ interface LinkGeneratorInterface {
    *     class will be applied to the link. It is important to use this
    *     sparingly since it is usually unnecessary and requires extra
    *     processing.
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated link and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedLink
    *   An HTML string containing a link to the given route and parameters.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedLink object is
-   *   returned, containing the generated link plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
+   *   returned, containing the generated link plus bubbleable metadata.
    *
    * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
    *   Thrown when the named route doesn't exist.
@@ -77,22 +77,22 @@ interface LinkGeneratorInterface {
    *   Thrown when a parameter value for a placeholder is not correct because it
    *   does not match the requirement.
    */
-  public function generate($text, Url $url, $collect_cacheability_metadata = FALSE);
+  public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE);
 
   /**
    * Renders a link from a link object.
    *
    * @param \Drupal\Core\Link $link
    *   A link object to convert to a string.
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated link and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedLink
    *   An HTML string containing a link to the given route and parameters.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedLink object is
-   *   returned, containing the generated link plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
+   *   returned, containing the generated link plus bubbleable metadata.
    */
-  public function generateFromLink(Link $link, $collect_cacheability_metadata = FALSE);
+  public function generateFromLink(Link $link, $collect_bubbleable_metadata = FALSE);
 
 }
diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
index 955680864e5f..e03d4c49eb85 100644
--- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
+++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
@@ -58,16 +58,16 @@ public function __construct(RequestStack $request_stack, ConfigFactoryInterface
    * This is a helper function that calls buildExternalUrl() or buildLocalUrl()
    * based on a check of whether the path is a valid external URL.
    */
-  public function assemble($uri, array $options = [], $collect_cacheability_metadata = FALSE) {
+  public function assemble($uri, array $options = [], $collect_bubbleable_metadata = FALSE) {
     // Note that UrlHelper::isExternal will return FALSE if the $uri has a
     // disallowed protocol.  This is later made safe since we always add at
     // least a leading slash.
     if (parse_url($uri, PHP_URL_SCHEME) === 'base') {
-      return $this->buildLocalUrl($uri, $options, $collect_cacheability_metadata);
+      return $this->buildLocalUrl($uri, $options, $collect_bubbleable_metadata);
     }
     elseif (UrlHelper::isExternal($uri)) {
       // UrlHelper::isExternal() only returns true for safe protocols.
-      return $this->buildExternalUrl($uri, $options, $collect_cacheability_metadata);
+      return $this->buildExternalUrl($uri, $options, $collect_bubbleable_metadata);
     }
     throw new \InvalidArgumentException(SafeMarkup::format('The URI "@uri" is invalid. You must use a valid URI scheme. Use base: for a path, e.g., to a Drupal file that needs the base path. Do not use this for internal paths controlled by Drupal.', ['@uri' => $uri]));
   }
@@ -75,7 +75,7 @@ public function assemble($uri, array $options = [], $collect_cacheability_metada
   /**
    * {@inheritdoc}
    */
-  protected function buildExternalUrl($uri, array $options = [], $collect_cacheability_metadata = FALSE) {
+  protected function buildExternalUrl($uri, array $options = [], $collect_bubbleable_metadata = FALSE) {
     $this->addOptionDefaults($options);
     // Split off the fragment.
     if (strpos($uri, '#') !== FALSE) {
@@ -100,14 +100,14 @@ protected function buildExternalUrl($uri, array $options = [], $collect_cacheabi
     }
     // Reassemble.
     $url = $uri . $options['fragment'];
-    return $collect_cacheability_metadata ? (new GeneratedUrl())->setGeneratedUrl($url) : $url;
+    return $collect_bubbleable_metadata ? (new GeneratedUrl())->setGeneratedUrl($url) : $url;
   }
 
   /**
    * {@inheritdoc}
    */
-  protected function buildLocalUrl($uri, array $options = [], $collect_cacheability_metadata = FALSE) {
-    $generated_url = $collect_cacheability_metadata ? new GeneratedUrl() : NULL;
+  protected function buildLocalUrl($uri, array $options = [], $collect_bubbleable_metadata = FALSE) {
+    $generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL;
 
     $this->addOptionDefaults($options);
     $request = $this->requestStack->getCurrentRequest();
@@ -149,7 +149,7 @@ protected function buildLocalUrl($uri, array $options = [], $collect_cacheabilit
       else {
         $base = $current_base_url;
       }
-      if ($collect_cacheability_metadata) {
+      if ($collect_bubbleable_metadata) {
         $generated_url->addCacheContexts(['url.site']);
       }
     }
@@ -162,7 +162,7 @@ protected function buildLocalUrl($uri, array $options = [], $collect_cacheabilit
     $uri = str_replace('%2F', '/', rawurlencode($prefix . $uri));
     $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : '';
     $url = $base . $options['script'] . $uri . $query . $options['fragment'];
-    return $collect_cacheability_metadata ? $generated_url->setGeneratedUrl($url) : $url;
+    return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php
index 9e8ca9071784..858c4bfe6cbd 100644
--- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php
+++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php
@@ -44,18 +44,18 @@ interface UnroutedUrlAssemblerInterface {
    *   - 'https': Whether this URL should point to a secure location. If not
    *     defined, the current scheme is used, so the user stays on HTTP or HTTPS
    *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP.
-   * @param bool $collect_cacheability_metadata
+   * @param bool $collect_bubbleable_metadata
    *   (optional) Defaults to FALSE. When TRUE, both the generated URL and its
-   *   associated cacheability metadata are returned.
+   *   associated bubbleable metadata are returned.
    *
    * @return string|\Drupal\Core\GeneratedUrl
    *   A string containing a relative or absolute URL.
-   *   When $collect_cacheability_metadata is TRUE, a GeneratedUrl object is
-   *   returned, containing the generated URL plus cacheability metadata.
+   *   When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is
+   *   returned, containing the generated URL plus bubbleable metadata.
    *
    * @throws \InvalidArgumentException
    *   Thrown when the passed in path has no scheme.
    */
-  public function assemble($uri, array $options = array(), $collect_cacheability_metadata = FALSE);
+  public function assemble($uri, array $options = array(), $collect_bubbleable_metadata = FALSE);
 
 }
diff --git a/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php b/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php
index 3b6adec2346a..635ecaa65935 100644
--- a/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php
+++ b/core/modules/help/tests/modules/help_test/src/SupernovaGenerator.php
@@ -39,7 +39,7 @@ public function generate($name, $parameters = array(), $referenceType = self::AB
   /**
    * {@inheritdoc}
    */
-  public function generateFromPath($path = NULL, $options = array(), $collect_cacheability_metadata = FALSE) {
+  public function generateFromPath($path = NULL, $options = array(), $collect_bubbleable_metadata = FALSE) {
     throw new \Exception();
   }
 
@@ -53,7 +53,7 @@ public function getPathFromRoute($name, $parameters = array()) {
   /**
    * {@inheritdoc}
    */
-  public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_cacheability_metadata = FALSE) {
+  public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE) {
     throw new \Exception();
   }
 
diff --git a/core/modules/language/src/HttpKernel/PathProcessorLanguage.php b/core/modules/language/src/HttpKernel/PathProcessorLanguage.php
index a69330994c6d..e25e2b5e0ae3 100644
--- a/core/modules/language/src/HttpKernel/PathProcessorLanguage.php
+++ b/core/modules/language/src/HttpKernel/PathProcessorLanguage.php
@@ -8,10 +8,10 @@
 namespace Drupal\language\HttpKernel;
 
 use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Drupal\language\LanguageNegotiatorInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -95,7 +95,7 @@ public function processInbound($path, Request $request) {
   /**
    * {@inheritdoc}
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     if (!isset($this->multilingual)) {
       $this->multilingual = $this->languageManager->isMultilingual();
     }
@@ -106,7 +106,7 @@ public function processOutbound($path, &$options = array(), Request $request = N
         $this->initProcessors($scope);
       }
       foreach ($this->processors[$scope] as $instance) {
-        $path = $instance->processOutbound($path, $options, $request, $cacheable_metadata);
+        $path = $instance->processOutbound($path, $options, $request, $bubbleable_metadata);
       }
       // No language dependent path allowed in this mode.
       if (empty($this->processors[$scope])) {
diff --git a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
index fe9500a4a0cc..9f4710956802 100644
--- a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
+++ b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationSession.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\language\Plugin\LanguageNegotiation;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Url;
 use Drupal\language\LanguageNegotiationMethodBase;
 use Drupal\language\LanguageSwitcherInterface;
@@ -86,7 +86,7 @@ public function persist(LanguageInterface $language) {
   /**
    * {@inheritdoc}
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     if ($request) {
       // The following values are not supposed to change during a single page
       // request processing.
@@ -115,10 +115,10 @@ public function processOutbound($path, &$options = array(), Request $request = N
         if (!isset($options['query'][$this->queryParam])) {
           $options['query'][$this->queryParam] = $this->queryValue;
         }
-        if ($cacheable_metadata) {
+        if ($bubbleable_metadata) {
           // Cached URLs that have been processed by this outbound path
           // processor must be:
-          $cacheable_metadata
+          $bubbleable_metadata
             // - invalidated when the language negotiation config changes, since
             //   another query parameter may be used to determine the language.
             ->addCacheTags($this->config->get('language.negotiation')->getCacheTags())
diff --git a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php
index 0c57d8b84a2e..ef6891c9b7b5 100644
--- a/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php
+++ b/core/modules/language/src/Plugin/LanguageNegotiation/LanguageNegotiationUrl.php
@@ -7,10 +7,10 @@
 
 namespace Drupal\language\Plugin\LanguageNegotiation;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Url;
 use Drupal\language\LanguageNegotiationMethodBase;
 use Drupal\language\LanguageSwitcherInterface;
@@ -123,7 +123,7 @@ public function processInbound($path, Request $request) {
   /**
    * Implements Drupal\Core\PathProcessor\InboundPathProcessorInterface::processOutbound().
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     $url_scheme = 'http';
     $port = 80;
     if ($request) {
@@ -144,8 +144,8 @@ public function processOutbound($path, &$options = array(), Request $request = N
     if ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) {
       if (is_object($options['language']) && !empty($config['prefixes'][$options['language']->getId()])) {
         $options['prefix'] = $config['prefixes'][$options['language']->getId()] . '/';
-        if ($cacheable_metadata) {
-          $cacheable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL]);
+        if ($bubbleable_metadata) {
+          $bubbleable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL]);
         }
       }
     }
@@ -184,8 +184,8 @@ public function processOutbound($path, &$options = array(), Request $request = N
 
         // Add Drupal's subfolder from the base_path if there is one.
         $options['base_url'] .= rtrim(base_path(), '/');
-        if ($cacheable_metadata) {
-          $cacheable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL, 'url.site']);
+        if ($bubbleable_metadata) {
+          $bubbleable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL, 'url.site']);
         }
       }
     }
diff --git a/core/modules/language/tests/src/Unit/LanguageNegotiationUrlTest.php b/core/modules/language/tests/src/Unit/LanguageNegotiationUrlTest.php
index 76d72b552147..34abb6105d87 100644
--- a/core/modules/language/tests/src/Unit/LanguageNegotiationUrlTest.php
+++ b/core/modules/language/tests/src/Unit/LanguageNegotiationUrlTest.php
@@ -8,8 +8,8 @@
 namespace Drupal\Tests\language\Unit {
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Session\UserSession;
 use Drupal\Tests\UnitTestCase;
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
@@ -91,10 +91,10 @@ public function testPathPrefix($prefix, $prefixes, $expected_langcode) {
     $method->setCurrentUser($this->user);
     $this->assertEquals($expected_langcode, $method->getLangcode($request));
 
-    $cacheability = new CacheableMetadata();
+    $cacheability = new BubbleableMetadata();
     $options = [];
     $method->processOutbound('foo', $options, $request, $cacheability);
-    $expected_cacheability = new CacheableMetadata();
+    $expected_cacheability = new BubbleableMetadata();
     if ($expected_langcode) {
       $this->assertSame($prefix . '/', $options['prefix']);
       $expected_cacheability->setCacheContexts(['languages:' . LanguageInterface::TYPE_URL]);
@@ -180,10 +180,10 @@ public function testDomain($http_host, $domains, $expected_langcode) {
     $method->setCurrentUser($this->user);
     $this->assertEquals($expected_langcode, $method->getLangcode($request));
 
-    $cacheability = new CacheableMetadata();
+    $cacheability = new BubbleableMetadata();
     $options = [];
     $this->assertSame('foo', $method->processOutbound('foo', $options, $request, $cacheability));
-    $expected_cacheability = new CacheableMetadata();
+    $expected_cacheability = new BubbleableMetadata();
     if ($expected_langcode !== FALSE && count($domains) > 1) {
       $expected_cacheability->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['languages:' . LanguageInterface::TYPE_URL, 'url.site']);
     }
diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentCacheabilityBubblingTest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentCacheabilityBubblingTest.php
index 80ab0503bbee..825f49388773 100644
--- a/core/modules/menu_link_content/src/Tests/MenuLinkContentCacheabilityBubblingTest.php
+++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentCacheabilityBubblingTest.php
@@ -8,9 +8,9 @@
 namespace Drupal\menu_link_content\Tests;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Menu\MenuTreeParameters;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\menu_link_content\Entity\MenuLinkContent;
 use Drupal\simpletest\KernelTestBase;
 use Drupal\user\Entity\User;
@@ -19,7 +19,7 @@
 use Symfony\Component\Routing\Route;
 
 /**
- * Ensures that rendered menu links bubble the necessary cacheability metadata
+ * Ensures that rendered menu links bubble the necessary bubbleable metadata
  * for outbound path/route processing.
  *
  * @group menu_link_content
@@ -47,7 +47,7 @@ protected function setUp() {
   }
 
   /**
-   * Tests bubbling of menu links' outbound route/path processing cacheability.
+   * Tests bubbleable metadata of menu links' outbound route/path processing.
    */
   public function testOutboundPathAndRouteProcessing() {
     \Drupal::service('router.builder')->rebuild();
@@ -66,7 +66,7 @@ public function testOutboundPathAndRouteProcessing() {
     $renderer = \Drupal::service('renderer');
 
 
-    $default_menu_cacheability = (new CacheableMetadata())
+    $default_menu_cacheability = (new BubbleableMetadata())
       ->setCacheMaxAge(Cache::PERMANENT)
       ->setCacheTags(['config:system.menu.tools'])
       ->setCacheContexts(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']);
@@ -87,26 +87,26 @@ public function testOutboundPathAndRouteProcessing() {
       // \Drupal\Core\RouteProcessor\RouteProcessorCurrent: 'route' cache context.
       [
         'uri' => 'route:<current>',
-        'cacheability' => (new CacheableMetadata())->setCacheContexts(['route']),
+        'cacheability' => (new BubbleableMetadata())->setCacheContexts(['route']),
       ],
-      // \Drupal\Core\Access\RouteProcessorCsrf: max-age = 0.
+      // \Drupal\Core\Access\RouteProcessorCsrf: placeholder.
       [
         'uri' => 'route:outbound_processing_test.route.csrf',
-        'cacheability' => (new CacheableMetadata())->setCacheMaxAge(0),
+        'cacheability' => (new BubbleableMetadata())->setCacheContexts(['session'])->setAttachments(['placeholders' => []]),
       ],
       // \Drupal\Core\PathProcessor\PathProcessorFront: permanently cacheable.
       [
         'uri' => 'internal:/',
-        'cacheability' => (new CacheableMetadata()),
+        'cacheability' => (new BubbleableMetadata()),
       ],
       // \Drupal\url_alter_test\PathProcessorTest: user entity's cache tags.
       [
         'uri' => 'internal:/user/1',
-        'cacheability' => (new CacheableMetadata())->setCacheTags(User::load(1)->getCacheTags()),
+        'cacheability' => (new BubbleableMetadata())->setCacheTags(User::load(1)->getCacheTags()),
       ],
       [
         'uri' => 'internal:/user/2',
-        'cacheability' => (new CacheableMetadata())->setCacheTags(User::load(2)->getCacheTags()),
+        'cacheability' => (new BubbleableMetadata())->setCacheTags(User::load(2)->getCacheTags()),
       ],
     ];
 
@@ -122,7 +122,7 @@ public function testOutboundPathAndRouteProcessing() {
       $renderer->renderRoot($build);
 
       $expected_cacheability = $default_menu_cacheability->merge($expectation['cacheability']);
-      $this->assertEqual($expected_cacheability, CacheableMetadata::createFromRenderArray($build));
+      $this->assertEqual($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
 
       $menu_link_content->delete();
     }
@@ -130,7 +130,7 @@ public function testOutboundPathAndRouteProcessing() {
     // Now test them all together in one menu: the rendered menu's cacheability
     // metadata should be the combination of the cacheability of all links, and
     // thus of all tested outbound path & route processors.
-    $expected_cacheability = new CacheableMetadata();
+    $expected_cacheability = new BubbleableMetadata();
     foreach ($test_cases as $expectation) {
       $menu_link_content = MenuLinkContent::create([
         'link' => ['uri' => $expectation['uri']],
@@ -143,7 +143,7 @@ public function testOutboundPathAndRouteProcessing() {
     $build = $menu_tree->build($tree);
     $renderer->renderRoot($build);
     $expected_cacheability = $expected_cacheability->merge($default_menu_cacheability);
-    $this->assertEqual($expected_cacheability, CacheableMetadata::createFromRenderArray($build));
+    $this->assertEqual($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
   }
 
 }
diff --git a/core/modules/system/src/Tests/Common/UrlTest.php b/core/modules/system/src/Tests/Common/UrlTest.php
index f823bfa34622..e5971391ba45 100644
--- a/core/modules/system/src/Tests/Common/UrlTest.php
+++ b/core/modules/system/src/Tests/Common/UrlTest.php
@@ -44,20 +44,20 @@ function testLinkXSS() {
   }
 
   /**
-   * Tests that #type=link bubbles outbound route/path processors' cacheability.
+   * Tests that #type=link bubbles outbound route/path processors' metadata.
    */
-  function testLinkCacheability() {
+  function testLinkBubbleableMetadata() {
     $cases = [
-      ['Regular link', 'internal:/user', [], ['contexts' => [], 'tags' => [], 'max-age' => Cache::PERMANENT]],
-      ['Regular link, absolute', 'internal:/user', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => [], 'max-age' => Cache::PERMANENT]],
-      ['Route processor link', 'route:system.run_cron', [], ['contexts' => [], 'tags' => [], 'max-age' => 0]],
-      ['Route processor link, absolute', 'route:system.run_cron', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => [], 'max-age' => 0]],
-      ['Path processor link', 'internal:/user/1', [], ['contexts' => [], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT]],
-      ['Path processor link, absolute', 'internal:/user/1', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT]],
+      ['Regular link', 'internal:/user', [], ['contexts' => [], 'tags' => [], 'max-age' => Cache::PERMANENT], []],
+      ['Regular link, absolute', 'internal:/user', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => [], 'max-age' => Cache::PERMANENT], []],
+      ['Route processor link', 'route:system.run_cron', [], ['contexts' => ['session'], 'tags' => [], 'max-age' => Cache::PERMANENT], ['placeholders' => []]],
+      ['Route processor link, absolute', 'route:system.run_cron', ['absolute' => TRUE], ['contexts' => ['url.site', 'session'], 'tags' => [], 'max-age' => Cache::PERMANENT], ['placeholders' => []]],
+      ['Path processor link', 'internal:/user/1', [], ['contexts' => [], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT], []],
+      ['Path processor link, absolute', 'internal:/user/1', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT], []],
     ];
 
     foreach ($cases as $case) {
-      list($title, $uri, $options, $expected_cacheability) = $case;
+      list($title, $uri, $options, $expected_cacheability, $expected_attachments) = $case;
       $expected_cacheability['contexts'] = Cache::mergeContexts($expected_cacheability['contexts'], ['languages:language_interface', 'theme', 'user.permissions']);
       $link = [
         '#type' => 'link',
@@ -68,6 +68,7 @@ function testLinkCacheability() {
       \Drupal::service('renderer')->renderRoot($link);
       $this->pass($title);
       $this->assertEqual($expected_cacheability, $link['#cache']);
+      $this->assertEqual($expected_attachments, $link['#attached']);
     }
   }
 
diff --git a/core/modules/system/src/Tests/RouteProcessor/RouteNoneTest.php b/core/modules/system/src/Tests/RouteProcessor/RouteNoneTest.php
index c46eb9c17a0e..551e4d8d6092 100644
--- a/core/modules/system/src/Tests/RouteProcessor/RouteNoneTest.php
+++ b/core/modules/system/src/Tests/RouteProcessor/RouteNoneTest.php
@@ -8,8 +8,8 @@
 namespace Drupal\system\Tests\RouteProcessor;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\GeneratedUrl;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\simpletest\KernelTestBase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -52,7 +52,7 @@ protected function setUp() {
    * Tests the output process.
    */
   public function testProcessOutbound() {
-    $expected_cacheability = (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT);
+    $expected_cacheability = (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT);
 
     $request_stack = \Drupal::requestStack();
     /** @var \Symfony\Component\Routing\RequestContext $request_context */
diff --git a/core/modules/system/src/Tests/RouteProcessor/RouteProcessorCurrentIntegrationTest.php b/core/modules/system/src/Tests/RouteProcessor/RouteProcessorCurrentIntegrationTest.php
index 4297ed1aba03..bc341a636b39 100644
--- a/core/modules/system/src/Tests/RouteProcessor/RouteProcessorCurrentIntegrationTest.php
+++ b/core/modules/system/src/Tests/RouteProcessor/RouteProcessorCurrentIntegrationTest.php
@@ -8,8 +8,8 @@
 namespace Drupal\system\Tests\RouteProcessor;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\GeneratedUrl;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\simpletest\KernelTestBase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -51,7 +51,7 @@ protected function setUp() {
    * Tests the output process.
    */
   public function testProcessOutbound() {
-    $expected_cacheability = (new CacheableMetadata())
+    $expected_cacheability = (new BubbleableMetadata())
       ->addCacheContexts(['route'])
       ->setCacheMaxAge(Cache::PERMANENT);
 
@@ -133,7 +133,7 @@ public function testProcessOutbound() {
     // In case we have no routing, the current route should point to the front,
     // and the cacheability does not depend on the 'route' cache context, since
     // no route was involved at all: this is fallback behavior.
-    $url = GeneratedUrl::createFromObject((new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT))->setGeneratedUrl('/');
+    $url = GeneratedUrl::createFromObject((new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT))->setGeneratedUrl('/');
     $this->assertEqual($url, $this->urlGenerator->generateFromRoute('<current>', [], [], TRUE));
   }
 
diff --git a/core/modules/system/tests/modules/url_alter_test/src/PathProcessorTest.php b/core/modules/system/tests/modules/url_alter_test/src/PathProcessorTest.php
index e30c1ca45eb4..c17dcd5c69c7 100644
--- a/core/modules/system/tests/modules/url_alter_test/src/PathProcessorTest.php
+++ b/core/modules/system/tests/modules/url_alter_test/src/PathProcessorTest.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\url_alter_test;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
+use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\Request;
 use Drupal\user\Entity\User;
 
@@ -44,14 +44,14 @@ public function processInbound($path, Request $request) {
   /**
    * Implements Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound().
    */
-  public function processOutbound($path, &$options = array(), Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
+  public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
     // Rewrite user/uid to user/username.
     if (preg_match('!^/user/([0-9]+)(/.*)?!', $path, $matches)) {
       if ($account = User::load($matches[1])) {
         $matches += array(2 => '');
         $path = '/user/' . $account->getUsername() . $matches[2];
-        if ($cacheable_metadata) {
-          $cacheable_metadata->addCacheTags($account->getCacheTags());
+        if ($bubbleable_metadata) {
+          $bubbleable_metadata->addCacheTags($account->getCacheTags());
         }
       }
     }
diff --git a/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php b/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php
index dc7a864e1a6f..a2ab1f1c3af6 100644
--- a/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php
+++ b/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Tests\Core\Access;
 
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Tests\UnitTestCase;
 use Drupal\Core\Access\RouteProcessorCsrf;
 use Symfony\Component\Routing\Route;
@@ -50,71 +50,73 @@ public function testProcessOutboundNoRequirement() {
     $route = new Route('/test-path');
     $parameters = array();
 
-    $cacheable_metadata = new CacheableMetadata();
-    $this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
     // No parameters should be added to the parameters array.
     $this->assertEmpty($parameters);
     // Cacheability of routes without a _csrf_token route requirement is
     // unaffected.
-    $this->assertEquals((new CacheableMetadata()), $cacheable_metadata);
+    $this->assertEquals((new BubbleableMetadata()), $bubbleable_metadata);
   }
 
   /**
    * Tests the processOutbound() method with a _csrf_token route requirement.
    */
   public function testProcessOutbound() {
-    $this->csrfToken->expects($this->once())
-      ->method('get')
-      // The leading '/' will be stripped from the path.
-      ->with('test-path')
-      ->will($this->returnValue('test_token'));
-
     $route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE'));
     $parameters = array();
 
-    $cacheable_metadata = new CacheableMetadata();
-    $this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
     // 'token' should be added to the parameters array.
     $this->assertArrayHasKey('token', $parameters);
-    $this->assertSame($parameters['token'], 'test_token');
-    // Cacheability of routes with a _csrf_token route requirement is max-age=0.
-    $this->assertEquals((new CacheableMetadata())->setCacheMaxAge(0), $cacheable_metadata);
+    // Bubbleable metadata of routes with a _csrf_token route requirement is a
+    // placeholder.
+    $path = 'test-path';
+    $placeholder = hash('sha1', $path);
+    $placeholder_render_array = [
+      '#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
+    ];
+    $this->assertSame($parameters['token'], $placeholder);
+    $this->assertEquals((new BubbleableMetadata())->setAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]), $bubbleable_metadata);
   }
 
   /**
    * Tests the processOutbound() method with a dynamic path and one replacement.
    */
   public function testProcessOutboundDynamicOne() {
-    $this->csrfToken->expects($this->once())
-      ->method('get')
-      ->with('test-path/100')
-      ->will($this->returnValue('test_token'));
-
     $route = new Route('/test-path/{slug}', array(), array('_csrf_token' => 'TRUE'));
     $parameters = array('slug' => 100);
 
-    $cacheable_metadata = new CacheableMetadata();
-    $this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
-    // Cacheability of routes with a _csrf_token route requirement is max-age=0.
-    $this->assertEquals((new CacheableMetadata())->setCacheMaxAge(0), $cacheable_metadata);
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
+    // Bubbleable metadata of routes with a _csrf_token route requirement is a
+    // placeholder.
+    $path = 'test-path/100';
+    $placeholder = hash('sha1', $path);
+    $placeholder_render_array = [
+      '#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
+    ];
+    $this->assertEquals((new BubbleableMetadata())->setAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]), $bubbleable_metadata);
   }
 
   /**
    * Tests the processOutbound() method with two parameter replacements.
    */
   public function testProcessOutboundDynamicTwo() {
-    $this->csrfToken->expects($this->once())
-      ->method('get')
-      ->with('100/test-path/test')
-      ->will($this->returnValue('test_token'));
-
     $route = new Route('{slug_1}/test-path/{slug_2}', array(), array('_csrf_token' => 'TRUE'));
     $parameters = array('slug_1' => 100, 'slug_2' => 'test');
 
-    $cacheable_metadata = new CacheableMetadata();
-    $this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
-    // Cacheability of routes with a _csrf_token route requirement is max-age=0.
-    $this->assertEquals((new CacheableMetadata())->setCacheMaxAge(0), $cacheable_metadata);
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
+    // Bubbleable metadata of routes with a _csrf_token route requirement is a
+    // placeholder.
+    $path = '100/test-path/test';
+    $placeholder = hash('sha1', $path);
+    $placeholder_render_array = [
+      '#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
+    ];
+    $this->assertEquals((new BubbleableMetadata())->setAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]), $bubbleable_metadata);
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php
index bf5203eab101..da6bef88bb21 100644
--- a/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php
+++ b/core/tests/Drupal/Tests/Core/PathProcessor/PathProcessorAliasTest.php
@@ -8,8 +8,8 @@
 namespace Drupal\Tests\Core\PathProcessor;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\PathProcessor\PathProcessorAlias;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -70,11 +70,11 @@ public function testProcessOutbound($path, array $options, $expected_path) {
         array('url', NULL, 'url'),
       )));
 
-    $cacheable_metadata = new CacheableMetadata();
-    $this->assertEquals($expected_path, $this->pathProcessor->processOutbound($path, $options, NULL, $cacheable_metadata));
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->assertEquals($expected_path, $this->pathProcessor->processOutbound($path, $options, NULL, $bubbleable_metadata));
     // Cacheability of paths replaced with path aliases is permanent.
     // @todo https://www.drupal.org/node/2480077
-    $this->assertEquals((new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), $cacheable_metadata);
+    $this->assertEquals((new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), $bubbleable_metadata);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/RouteProcessor/RouteProcessorManagerTest.php b/core/tests/Drupal/Tests/Core/RouteProcessor/RouteProcessorManagerTest.php
index 77d31ff94e30..ca1cbbcb941d 100644
--- a/core/tests/Drupal/Tests/Core/RouteProcessor/RouteProcessorManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/RouteProcessor/RouteProcessorManagerTest.php
@@ -8,7 +8,7 @@
 namespace Drupal\Tests\Core\RouteProcessor;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\RouteProcessor\RouteProcessorManager;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\Routing\Route;
@@ -49,10 +49,10 @@ public function testRouteProcessorManager() {
       $this->processorManager->addOutbound($processor, $priority);
     }
 
-    $cacheable_metadata = new CacheableMetadata();
-    $this->processorManager->processOutbound($route_name, $route, $parameters, $cacheable_metadata);
+    $bubbleable_metadata = new BubbleableMetadata();
+    $this->processorManager->processOutbound($route_name, $route, $parameters, $bubbleable_metadata);
     // Default cacheability is: permanently cacheable, no cache tags/contexts.
-    $this->assertEquals((new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), $cacheable_metadata);
+    $this->assertEquals((new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), $bubbleable_metadata);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php b/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
index 57edd5173523..e78a0b07ce51 100644
--- a/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
@@ -8,10 +8,10 @@
 namespace Drupal\Tests\Core\Routing;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\PathProcessor\PathProcessorAlias;
 use Drupal\Core\PathProcessor\PathProcessorManager;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Routing\RequestContext;
 use Drupal\Core\Routing\UrlGenerator;
 use Drupal\Tests\UnitTestCase;
@@ -185,7 +185,7 @@ public function testAliasGeneration() {
 
 
     // Check that the two generate methods return the same result.
-    $this->assertGenerateFromRoute('test_1', [], [], $url, (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_1', [], [], $url, (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     $path = $this->generator->getPathFromRoute('test_1');
     $this->assertEquals('test/one', $path);
@@ -217,13 +217,13 @@ public function testAliasGenerationWithParameters() {
 
     $options = array('fragment' => 'top');
     // Extra parameters should appear in the query string.
-    $this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, '/hello/world?zoo=5#top', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, '/hello/world?zoo=5#top', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     $options = array('query' => array('page' => '1'), 'fragment' => 'bottom');
-    $this->assertGenerateFromRoute('test_2', ['narf' => 5], $options, '/goodbye/cruel/world?page=1#bottom', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_2', ['narf' => 5], $options, '/goodbye/cruel/world?page=1#bottom', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     // Changing the parameters, the route still matches but there is no alias.
-    $this->assertGenerateFromRoute('test_2', ['narf' => 7], $options, '/test/two/7?page=1#bottom', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_2', ['narf' => 7], $options, '/test/two/7?page=1#bottom', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     $path = $this->generator->getPathFromRoute('test_2', array('narf' => '5'));
     $this->assertEquals('test/two/5', $path);
@@ -235,7 +235,7 @@ public function testAliasGenerationWithParameters() {
    * @dataProvider providerTestAliasGenerationWithOptions
    */
   public function testAliasGenerationWithOptions($route_name, $route_parameters, $options, $expected) {
-    $this->assertGenerateFromRoute($route_name, $route_parameters, $options, $expected, (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute($route_name, $route_parameters, $options, $expected, (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
   }
 
   /**
@@ -299,7 +299,7 @@ public function testAbsoluteURLGeneration() {
 
     $options = array('absolute' => TRUE, 'fragment' => 'top');
     // Extra parameters should appear in the query string.
-    $this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://localhost/hello/world?zoo=5#top', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
+    $this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://localhost/hello/world?zoo=5#top', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
   }
 
   /**
@@ -307,13 +307,13 @@ public function testAbsoluteURLGeneration() {
    */
   public function testBaseURLGeneration() {
     $options = array('base_url' => 'http://www.example.com:8888');
-    $this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     $options = array('base_url' => 'http://www.example.com:8888', 'https' => TRUE);
-    $this->assertGenerateFromRoute('test_1', [], $options, 'https://www.example.com:8888/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_1', [], $options, 'https://www.example.com:8888/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     $options = array('base_url' => 'https://www.example.com:8888', 'https' => FALSE);
-    $this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
 
     $this->routeProcessorManager->expects($this->exactly(2))
       ->method('processOutbound')
@@ -321,7 +321,7 @@ public function testBaseURLGeneration() {
 
     $options = array('base_url' => 'http://www.example.com:8888', 'fragment' => 'top');
     // Extra parameters should appear in the query string.
-    $this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://www.example.com:8888/hello/world?zoo=5#top', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
+    $this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://www.example.com:8888/hello/world?zoo=5#top', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
   }
 
   /**
@@ -338,7 +338,7 @@ public function testUrlGenerationWithHttpsRequirement() {
       ->with($this->anything());
 
     $options = array('absolute' => TRUE, 'https' => TRUE);
-    $this->assertGenerateFromRoute('test_1', [], $options, 'https://localhost/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
+    $this->assertGenerateFromRoute('test_1', [], $options, 'https://localhost/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
   }
 
   /**
@@ -362,8 +362,8 @@ public function testPathBasedURLGeneration() {
         $request->headers->set('host', ['www.example.com']);
         $this->requestStack->push($request);
 
-        // Determine the expected cacheability.
-        $expected_cacheability = (new CacheableMetadata())
+        // Determine the expected bubbleable metadata.
+        $expected_cacheability = (new BubbleableMetadata())
           ->setCacheContexts($absolute ? ['url.site'] : [])
           ->setCacheMaxAge(Cache::PERMANENT);
 
@@ -374,42 +374,42 @@ public function testPathBasedURLGeneration() {
         $this->assertEquals($url, $result, "$url == $result");
         $generated_url = $this->generator->generateFromPath('node/123', array('absolute' => $absolute), TRUE);
         $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
 
         $url = $base . 'node/123#foo';
         $result = $this->generator->generateFromPath('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
         $this->assertEquals($url, $result, "$url == $result");
         $generated_url = $this->generator->generateFromPath('node/123', array('fragment' => 'foo', 'absolute' => $absolute), TRUE);
         $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
 
         $url = $base . 'node/123?foo';
         $result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
         $this->assertEquals($url, $result, "$url == $result");
         $generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute), TRUE);
         $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
 
         $url = $base . 'node/123?foo=bar&bar=baz';
         $result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
         $this->assertEquals($url, $result, "$url == $result");
         $generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute), TRUE);
         $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
 
         $url = $base . 'node/123?foo#bar';
         $result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
         $this->assertEquals($url, $result, "$url == $result");
         $generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute), TRUE);
         $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
 
         $url = $base;
         $result = $this->generator->generateFromPath('<front>', array('absolute' => $absolute));
         $this->assertEquals($url, $result, "$url == $result");
         $generated_url = $this->generator->generateFromPath('<front>', array('absolute' => $absolute), TRUE);
         $this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
-        $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+        $this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
       }
     }
   }
@@ -425,10 +425,10 @@ public function testPathBasedURLGeneration() {
    *   The options to test.
    * @param $expected_url
    *   The expected generated URL string.
-   * @param \Drupal\Core\Cache\CacheableMetadata $expected_cacheability
-   *   The expected generated cacheability metadata.
+   * @param \Drupal\Core\Render\BubbleableMetadata $expected_bubbleable_metadata
+   *   The expected generated bubbleable metadata.
    */
-  protected function assertGenerateFromRoute($route_name, array $route_parameters, array $options, $expected_url, CacheableMetadata $expected_cacheability) {
+  protected function assertGenerateFromRoute($route_name, array $route_parameters, array $options, $expected_url, BubbleableMetadata $expected_bubbleable_metadata) {
     // First, test with $collect_cacheability_metadata set to the default value.
     $url = $this->generator->generateFromRoute($route_name, $route_parameters, $options);
     $this->assertSame($expected_url, $url);
@@ -436,7 +436,7 @@ protected function assertGenerateFromRoute($route_name, array $route_parameters,
     // Second, test with it set to TRUE.
     $generated_url = $this->generator->generateFromRoute($route_name, $route_parameters, $options, TRUE);
     $this->assertSame($expected_url, $generated_url->getGeneratedUrl());
-    $this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
+    $this->assertEquals($expected_bubbleable_metadata, BubbleableMetadata::createFromObject($generated_url));
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index 296a8b509c23..f1c538c0a996 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -89,8 +89,8 @@ protected function setUp() {
       array('non-existent', NULL, FALSE, 'non-existent'),
     );
 
-    // $this->map has $collect_cacheability_metadata = FALSE; also generate the
-    // $collect_cacheability_metadata = TRUE case for ::generateFromRoute().
+    // $this->map has $collect_bubbleable_metadata = FALSE; also generate the
+    // $collect_bubbleable_metadata = TRUE case for ::generateFromRoute().
     $generate_from_route_map = [];
     foreach ($this->map as $values) {
       $generate_from_route_map[] = $values;
@@ -382,7 +382,7 @@ public function testToString($urls) {
       $this->assertSame($path, $url->toString());
       $generated_url = $url->toString(TRUE);
       $this->assertSame($path, $generated_url->getGeneratedUrl());
-      $this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_url);
+      $this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_url);
     }
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
index ae8f54e3f0e2..9392d22cf2d2 100644
--- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
@@ -469,12 +469,12 @@ public function testGenerateActive() {
   }
 
   /**
-   * Tests the LinkGenerator's support for collecting cacheability metadata.
+   * Tests the LinkGenerator's support for collecting bubbleable metadata.
    *
    * @see \Drupal\Core\Utility\LinkGenerator::generate()
    * @see \Drupal\Core\Utility\LinkGenerator::generateFromLink()
    */
-  public function testGenerateCacheability() {
+  public function testGenerateBubbleableMetadata() {
     $options = ['query' => [], 'language' => NULL, 'set_active_class' => FALSE, 'absolute' => FALSE];
     $this->urlGenerator->expects($this->any())
       ->method('generateFromRoute')
@@ -491,14 +491,14 @@ public function testGenerateCacheability() {
     $this->assertSame($expected_link_markup, $this->linkGenerator->generate('Test', $url));
     $generated_link = $this->linkGenerator->generate('Test', $url, TRUE);
     $this->assertSame($expected_link_markup, $generated_link->getGeneratedLink());
-    $this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_link);
+    $this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
 
     // Test ::generateFromLink().
     $link = new Link('Test', $url);
     $this->assertSame($expected_link_markup, $this->linkGenerator->generateFromLink($link));
     $generated_link = $this->linkGenerator->generateFromLink($link, TRUE);
     $this->assertSame($expected_link_markup, $generated_link->getGeneratedLink());
-    $this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_link);
+    $this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
index 98fab074a356..98abf4847d0f 100644
--- a/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Tests\Core\Utility;
 
-use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\GeneratedUrl;
+use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Utility\UnroutedUrlAssembler;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
@@ -87,7 +87,7 @@ public function testAssembleWithExternalUrl($uri, array $options, $expected) {
    $this->assertEquals($expected, $this->unroutedUrlAssembler->assemble($uri, $options));
    $generated_url = $this->unroutedUrlAssembler->assemble($uri, $options, TRUE);
    $this->assertEquals($expected, $generated_url->getGeneratedUrl());
-   $this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_url);
+   $this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_url);
   }
 
   /**
@@ -153,9 +153,9 @@ public function testAssembleWithEnabledProcessing() {
     $this->setupRequestStack(FALSE);
     $this->pathProcessor->expects($this->exactly(2))
       ->method('processOutbound')
-      ->willReturnCallback(function($path, &$options = [], Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
-        if ($cacheable_metadata) {
-          $cacheable_metadata->setCacheContexts(['some-cache-context']);
+      ->willReturnCallback(function($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
+        if ($bubbleable_metadata) {
+          $bubbleable_metadata->setCacheContexts(['some-cache-context']);
         }
         return 'test-other-uri';
       });
-- 
GitLab