diff --git a/core/includes/common.inc b/core/includes/common.inc
index 53e0be5c91..d37a8db79d 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -14,6 +14,7 @@
 use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Extension\VersionChecker;
 use Drupal\Core\Render\Element\Link;
 use Drupal\Core\Render\Markup;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
@@ -1213,16 +1214,13 @@ function debug($data, $label = NULL, $print_r = TRUE) {
  *   NULL if compatible, otherwise the original dependency version string that
  *   caused the incompatibility.
  *
- * @see \Drupal\Core\Extension\ModuleHandler::parseDependency()
+ * @see \Drupal\Core\Extension\VersionChecker::checkIncompatibility
+ *
+ * @deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use
+ *   \Drupal\Core\Extension\ModuleHandler::checkIncompatibility() instead.
  */
 function drupal_check_incompatibility($v, $current_version) {
-  if (!empty($v['versions'])) {
-    foreach ($v['versions'] as $required_version) {
-      if ((isset($required_version['op']) && !version_compare($current_version, $required_version['version'], $required_version['op']))) {
-        return $v['original_version'];
-      }
-    }
-  }
+  return VersionChecker::checkIncompatibility($v, $current_version);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index 2a2113ff13..3097304bf1 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -224,7 +224,7 @@ public function buildModuleDependencies(array $modules) {
       $graph[$module->getName()]['edges'] = [];
       if (isset($module->info['dependencies']) && is_array($module->info['dependencies'])) {
         foreach ($module->info['dependencies'] as $dependency) {
-          $dependency_data = static::parseDependency($dependency);
+          $dependency_data = VersionChecker::parseDependency($dependency);
           $graph[$module->getName()]['edges'][$dependency_data['name']] = $dependency_data;
         }
       }
@@ -715,51 +715,13 @@ protected function verifyImplementations(&$implementations, $hook) {
    *     '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'.
    *   Callers should pass this structure to drupal_check_incompatibility().
    *
-   * @see drupal_check_incompatibility()
+   * @see \Drupal\Core\Extension\VersionChecker::parseDependency
+   *
+   * @deprecated in Drupal 8.6.0, will be removed before Drupal 9.0.0.
+   *   Use \Drupal\Core\Extension\VersionChecker::parseDependency() instead.
    */
   public static function parseDependency($dependency) {
-    $value = [];
-    // Split out the optional project name.
-    if (strpos($dependency, ':') !== FALSE) {
-      list($project_name, $dependency) = explode(':', $dependency);
-      $value['project'] = $project_name;
-    }
-    // We use named subpatterns and support every op that version_compare
-    // supports. Also, op is optional and defaults to equals.
-    $p_op = '(?<operation>!=|==|=|<|<=|>|>=|<>)?';
-    // Core version is always optional: 8.x-2.x and 2.x is treated the same.
-    $p_core = '(?:' . preg_quote(\Drupal::CORE_COMPATIBILITY) . '-)?';
-    $p_major = '(?<major>\d+)';
-    // By setting the minor version to x, branches can be matched.
-    $p_minor = '(?<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
-    $parts = explode('(', $dependency, 2);
-    $value['name'] = trim($parts[0]);
-    if (isset($parts[1])) {
-      $value['original_version'] = ' (' . $parts[1];
-      foreach (explode(',', $parts[1]) as $version) {
-        if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) {
-          $op = !empty($matches['operation']) ? $matches['operation'] : '=';
-          if ($matches['minor'] == 'x') {
-            // Drupal considers "2.x" to mean any version that begins with
-            // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(),
-            // on the other hand, treats "x" as a string; so to
-            // version_compare(), "2.x" is considered less than 2.0. This
-            // means that >=2.x and <2.x are handled by version_compare()
-            // as we need, but > and <= are not.
-            if ($op == '>' || $op == '<=') {
-              $matches['major']++;
-            }
-            // Equivalence can be checked by adding two restrictions.
-            if ($op == '=' || $op == '==') {
-              $value['versions'][] = ['op' => '<', 'version' => ($matches['major'] + 1) . '.x'];
-              $op = '>=';
-            }
-          }
-          $value['versions'][] = ['op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']];
-        }
-      }
-    }
-    return $value;
+    return VersionChecker::parseDependency($dependency);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Extension/VersionChecker.php b/core/lib/Drupal/Core/Extension/VersionChecker.php
new file mode 100644
index 0000000000..0824c73412
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/VersionChecker.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\Core\Extension;
+
+/**
+ * Provides utility functions for checking versions of Drupal extensions.
+ */
+class VersionChecker {
+
+  /**
+   * Checks whether a version is compatible with a given dependency.
+   *
+   * @param array $version_info
+   *   A parsed dependency structure e.g. from
+   *   \Drupal\Core\Extension\VersionChecker::parseDependency.
+   * @param string $current_version
+   *   The version to check against (like 4.2).
+   *
+   * @return string|null
+   *   NULL if compatible, otherwise the original dependency version string that
+   *   caused the incompatibility.
+   *
+   * @see \Drupal\Core\Extension\VersionChecker::parseDependency()
+   */
+  public static function checkIncompatibility(array $version_info, $current_version) {
+    if (!empty($version_info['versions'])) {
+      foreach ($version_info['versions'] as $required_version) {
+        if ((isset($required_version['op']) && !version_compare($current_version, $required_version['version'], $required_version['op']))) {
+          return $version_info['original_version'];
+        }
+      }
+    }
+  }
+
+  /**
+   * Parses a dependency for comparison by drupal_check_incompatibility().
+   *
+   * @param string $dependency
+   *   A dependency string, which specifies a module dependency, and optionally
+   *   the project it comes from and versions that are supported. Supported
+   *   formats include:
+   *   - 'module'
+   *   - 'project:module'
+   *   - 'project:module (>=version, version)'
+   *
+   * @return array
+   *   An associative array with three keys:
+   *   - 'name' includes the name of the thing to depend on (e.g. 'foo').
+   *   - 'original_version' contains the original version string (which can be
+   *     used in the UI for reporting incompatibilities).
+   *   - 'versions' is a list of associative arrays, each containing the keys
+   *     'op' and 'version'. 'op' can be one of: '=', '==', '!=', '<>', '<',
+   *     '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'.
+   *   Callers should pass this structure to
+   *   \Drupal\Core\Extension\VersionChecker::checkIncompatibility().
+   *
+   * @see \Drupal\Core\Extension\VersionChecker::checkIncompatibility()
+   */
+  public static function parseDependency($dependency) {
+    $value = [];
+    // Split out the optional project name.
+    if (strpos($dependency, ':') !== FALSE) {
+      list($project_name, $dependency) = explode(':', $dependency);
+      $value['project'] = $project_name;
+    }
+    // We use named subpatterns and support every op that version_compare
+    // supports. Also, op is optional and defaults to equals.
+    $p_op = '(?<operation>!=|==|=|<|<=|>|>=|<>)?';
+    // Core version is always optional: 8.x-2.x and 2.x is treated the same.
+    $p_core = '(?:' . preg_quote(\Drupal::CORE_COMPATIBILITY) . '-)?';
+    $p_major = '(?<major>\d+)';
+    // By setting the minor version to x, branches can be matched.
+    $p_minor = '(?<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
+    $parts = explode('(', $dependency, 2);
+    $value['name'] = trim($parts[0]);
+    if (isset($parts[1])) {
+      $value['original_version'] = ' (' . $parts[1];
+      foreach (explode(',', $parts[1]) as $version) {
+        if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) {
+          $op = !empty($matches['operation']) ? $matches['operation'] : '=';
+          if ($matches['minor'] == 'x') {
+            // Drupal considers "2.x" to mean any version that begins with
+            // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(),
+            // on the other hand, treats "x" as a string; so to
+            // version_compare(), "2.x" is considered less than 2.0. This
+            // means that >=2.x and <2.x are handled by version_compare()
+            // as we need, but > and <= are not.
+            if ($op == '>' || $op == '<=') {
+              $matches['major']++;
+            }
+            // Equivalence can be checked by adding two restrictions.
+            if ($op == '=' || $op == '==') {
+              $value['versions'][] = ['op' => '<', 'version' => ($matches['major'] + 1) . '.x'];
+              $op = '>=';
+            }
+          }
+          $value['versions'][] = ['op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']];
+        }
+      }
+    }
+    return $value;
+  }
+
+}
diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php
index 3ff6c3d09d..a4b2dccc23 100644
--- a/core/modules/system/src/Form/ModulesListForm.php
+++ b/core/modules/system/src/Form/ModulesListForm.php
@@ -9,6 +9,7 @@
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Extension\ModuleInstallerInterface;
+use Drupal\Core\Extension\VersionChecker;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
@@ -310,7 +311,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
         $name = $modules[$dependency]->info['name'];
         // Disable the module's checkbox if it is incompatible with the
         // dependency's version.
-        if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) {
+        if ($incompatible_version = VersionChecker::checkIncompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) {
           $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> version @version)', [
             '@module' => $name . $incompatible_version,
             '@version' => $modules[$dependency]->info['version'],
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index ed05621335..f479842047 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\OpCodeCache;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Extension\VersionChecker;
 use Drupal\Core\Path\AliasStorage;
 use Drupal\Core\Url;
 use Drupal\Core\Database\Database;
@@ -817,7 +818,7 @@ function system_requirements($phase) {
         $required_file = $files[$required_module];
         $required_name = $required_file->info['name'];
         $version = str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $required_file->info['version']);
-        $compatibility = drupal_check_incompatibility($requirement, $version);
+        $compatibility = VersionChecker::checkIncompatibility($requirement, $version);
         if ($compatibility) {
           $compatibility = rtrim(substr($compatibility, 2), ')');
           $requirements["$module-$required_module"] = [
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index bb82d4b19f..0d152f70a5 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -9,6 +9,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Asset\AttachedAssetsInterface;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Extension\VersionChecker;
 use Drupal\Core\Queue\QueueGarbageCollectionInterface;
 use Drupal\Core\Database\Query\AlterableInterface;
 use Drupal\Core\Extension\Extension;
@@ -20,7 +21,6 @@
 use Drupal\Core\Routing\StackedRouteMatchInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Menu\MenuTreeParameters;
-use Drupal\Core\Extension\ModuleHandler;
 use Drupal\Core\Url;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\user\UserInterface;
@@ -1007,7 +1007,7 @@ function _system_rebuild_module_data_ensure_required($module, &$modules) {
   @trigger_error("_system_rebuild_module_data_ensure_required() is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. This function is no longer used in Drupal core. See https://www.drupal.org/node/2709919", E_USER_DEPRECATED);
   if (!empty($module->info['required'])) {
     foreach ($module->info['dependencies'] as $dependency) {
-      $dependency_name = ModuleHandler::parseDependency($dependency)['name'];
+      $dependency_name = VersionChecker::parseDependency($dependency)['name'];
       if (!isset($modules[$dependency_name]->info['required'])) {
         $modules[$dependency_name]->info['required'] = TRUE;
         $modules[$dependency_name]->info['explanation'] = t('Dependency of required module @module', ['@module' => $module->info['name']]);
diff --git a/core/tests/Drupal/Tests/Core/Extension/VersionCheckerTest.php b/core/tests/Drupal/Tests/Core/Extension/VersionCheckerTest.php
new file mode 100644
index 0000000000..3a9e073c70
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Extension/VersionCheckerTest.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Drupal\Tests\Core\Extension;
+
+use Drupal\Core\Extension\VersionChecker;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Extension\VersionChecker
+ * @group Extension
+ */
+class VersionCheckerTest extends TestCase {
+
+  /**
+   * @covers ::checkIncompatibility
+   * @dataProvider providerTestCheckIncompability
+   */
+  public function testCheckIncompatibility(array $version_info, $current_version, $result) {
+    $this->assertEquals($result, VersionChecker::checkIncompatibility($version_info, $current_version));
+  }
+
+  /**
+   * Provider for testCheckIncompatibility.
+   */
+  public function providerTestCheckIncompability() {
+    $data = [];
+
+    $data['no-dependencies'] = [[], '8.1.x', NULL];
+
+    $test_cases = $this->dependencyProvider();
+
+    // First tests the equal comparison.
+
+    // Stable version.
+    $data['views_ui(=8.x-1.0)-1.0'] = [$test_cases['views_ui(8.x-1.0)'][1], '1.0', NULL];
+    $data['views_ui(=8.x-1.0)-1.1'] = [$test_cases['views_ui(8.x-1.0)'][1], '1.1', ' (8.x-1.0)'];
+    $data['views_ui(=8.x-1.0)-0.9'] = [$test_cases['views_ui(8.x-1.0)'][1], '0.9', ' (8.x-1.0)'];
+
+    // Alpha version
+    $data['views_ui(8.x-1.1-alpha12)-alpha12'] = [$test_cases['views_ui(8.x-1.1-alpha12)'][1], '1.1-alpha12', NULL];
+    $data['views_ui(8.x-1.1-alpha12)-alpha10'] = [$test_cases['views_ui(8.x-1.1-alpha12)'][1], '1.1-alpha10', ' (8.x-1.1-alpha12)'];
+    $data['views_ui(8.x-1.1-alpha12)-beta1'] = [$test_cases['views_ui(8.x-1.1-alpha12)'][1], '1.1-beta1', ' (8.x-1.1-alpha12)'];
+
+    // Test greater than.
+    $data['views_ui(>8.x-1.x)-2.0'] = [$test_cases['views_ui(>8.x-1.x)'][1], '2.0', NULL];
+    $data['views_ui(>8.x-1.x)-1.1'] = [$test_cases['views_ui(>8.x-1.x)'][1], '1.1', ' (>8.x-1.x)'];
+    $data['views_ui(>8.x-1.x)-0.9'] = [$test_cases['views_ui(>8.x-1.x)'][1], '0.9', ' (>8.x-1.x)'];
+
+    // Test Less than or equal.
+    $data['views_ui(<= 8.x-1.x)-2.0'] = [$test_cases['views_ui(<= 8.x-1.x)'][1], '2.0', ' (<= 8.x-1.x)'];
+    $data['views_ui(<= 8.x-1.x)-1.9'] = [$test_cases['views_ui(<= 8.x-1.x)'][1], '1.9', NULL];
+    $data['views_ui(<= 8.x-1.x)-1.1'] = [$test_cases['views_ui(<= 8.x-1.x)'][1], '1.1', NULL];
+    $data['views_ui(<= 8.x-1.x)-0.9'] = [$test_cases['views_ui(<= 8.x-1.x)'][1], '0.9', NULL];
+
+    return $data;
+  }
+
+
+  /**
+   * @dataProvider dependencyProvider
+   * @covers ::parseDependency
+   */
+  public function testParseDependency($dependency, $expected) {
+    $version = VersionChecker::parseDependency($dependency);
+    $this->assertEquals($expected, $version);
+  }
+
+  /**
+   * Provider for testing dependency parsing.
+   */
+  public function dependencyProvider() {
+    return [
+      'system' => ['system', ['name' => 'system']],
+      'taxonomy' => ['taxonomy', ['name' => 'taxonomy']],
+      'views' => ['views', ['name' => 'views']],
+      'views_ui(8.x-1.0)' => ['views_ui(8.x-1.0)', ['name' => 'views_ui', 'original_version' => ' (8.x-1.0)', 'versions' => [['op' => '=', 'version' => '1.0']]]],
+      // Not supported?.
+      // array('views_ui(8.x-1.1-beta)', array('name' => 'views_ui', 'original_version' => ' (8.x-1.1-beta)', 'versions' => array(array('op' => '=', 'version' => '1.1-beta')))),
+      'views_ui(8.x-1.1-alpha12)' => ['views_ui(8.x-1.1-alpha12)', ['name' => 'views_ui', 'original_version' => ' (8.x-1.1-alpha12)', 'versions' => [['op' => '=', 'version' => '1.1-alpha12']]]],
+      'views_ui(8.x-1.1-beta8)' => ['views_ui(8.x-1.1-beta8)', ['name' => 'views_ui', 'original_version' => ' (8.x-1.1-beta8)', 'versions' => [['op' => '=', 'version' => '1.1-beta8']]]],
+      'views_ui(8.x-1.1-rc11)' => ['views_ui(8.x-1.1-rc11)', ['name' => 'views_ui', 'original_version' => ' (8.x-1.1-rc11)', 'versions' => [['op' => '=', 'version' => '1.1-rc11']]]],
+      'views_ui(8.x-1.12)' => ['views_ui(8.x-1.12)', ['name' => 'views_ui', 'original_version' => ' (8.x-1.12)', 'versions' => [['op' => '=', 'version' => '1.12']]]],
+      'views_ui(8.x-1.x)' => ['views_ui(8.x-1.x)', ['name' => 'views_ui', 'original_version' => ' (8.x-1.x)', 'versions' => [['op' => '<', 'version' => '2.x'], ['op' => '>=', 'version' => '1.x']]]],
+      'views_ui( <= 8.x-1.x)' => ['views_ui( <= 8.x-1.x)', ['name' => 'views_ui', 'original_version' => ' ( <= 8.x-1.x)', 'versions' => [['op' => '<=', 'version' => '2.x']]]],
+      'views_ui(<= 8.x-1.x)' => ['views_ui(<= 8.x-1.x)', ['name' => 'views_ui', 'original_version' => ' (<= 8.x-1.x)', 'versions' => [['op' => '<=', 'version' => '2.x']]]],
+      'views_ui( <=8.x-1.x)' => ['views_ui( <=8.x-1.x)', ['name' => 'views_ui', 'original_version' => ' ( <=8.x-1.x)', 'versions' => [['op' => '<=', 'version' => '2.x']]]],
+      'views_ui(>8.x-1.x)' => ['views_ui(>8.x-1.x)', ['name' => 'views_ui', 'original_version' => ' (>8.x-1.x)', 'versions' => [['op' => '>', 'version' => '2.x']]]],
+      'drupal:views_ui(>8.x-1.x)' => ['drupal:views_ui(>8.x-1.x)', ['project' => 'drupal', 'name' => 'views_ui', 'original_version' => ' (>8.x-1.x)', 'versions' => [['op' => '>', 'version' => '2.x']]]],
+    ];
+  }
+
+}
