diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/impl/PyVersionCheck.kt b/python/python-psi-api/src/com/jetbrains/python/psi/impl/PyVersionCheck.kt
deleted file mode 100644
index dbe544964f4c..000000000000
--- a/python/python-psi-api/src/com/jetbrains/python/psi/impl/PyVersionCheck.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.jetbrains.python.psi.impl
-
-import com.google.common.collect.ImmutableRangeSet
-import com.google.common.collect.Range
-import com.intellij.openapi.util.Version
-import com.intellij.psi.util.QualifiedName
-import com.jetbrains.python.PyTokenTypes
-import com.jetbrains.python.psi.*
-import org.jetbrains.annotations.ApiStatus
-import java.math.BigInteger
-
-@ApiStatus.Internal
-object PyVersionCheck {
- /**
- * @return Version ranges if {@code expression} is a version check, {@code null} otherwise
- *
- * @see Version and Platform Checks
- */
- @JvmStatic
- fun convertToVersionRanges(ifPart: PyIfPart): ImmutableRangeSet? {
- return ifPart.condition?.let(PyVersionCheck::convertToVersionRanges)
- }
-
- fun convertToVersionRanges(expression: PyExpression): ImmutableRangeSet? {
- val binaryExpr = PyPsiUtils.flattenParens(expression) as? PyBinaryExpression ?: return null
- when (val operator = binaryExpr.operator) {
- PyTokenTypes.AND_KEYWORD, PyTokenTypes.OR_KEYWORD -> {
- val rhs = binaryExpr.rightExpression ?: return null
- val ranges1 = convertToVersionRanges(binaryExpr.leftExpression) ?: return null
- val ranges2 = convertToVersionRanges(rhs) ?: return null
- return if (operator === PyTokenTypes.AND_KEYWORD)
- ranges1.intersection(ranges2)
- else
- ranges1.union(ranges2)
- }
-
- PyTokenTypes.LT, PyTokenTypes.GT, PyTokenTypes.LE, PyTokenTypes.GE -> {
- val refExpr = PyPsiUtils.flattenParens(binaryExpr.leftExpression) as? PyReferenceExpression ?: return null
- if (SYS_VERSION_INFO_QUALIFIED_NAME != refExpr.asQualifiedName()) return null
-
- val tuple = PyPsiUtils.flattenParens(binaryExpr.rightExpression) as? PyTupleExpression ?: return null
- val version = evaluateVersion(tuple) ?: return null
-
- val range = when (operator) {
- PyTokenTypes.LT -> Range.lessThan(version)
- PyTokenTypes.GT -> Range.greaterThan(version)
- PyTokenTypes.LE -> Range.atMost(version)
- PyTokenTypes.GE -> Range.atLeast(version)
- else -> throw IllegalStateException()
- }
- return ImmutableRangeSet.of(range)
- }
-
- else -> return null
- }
- }
-
- private val SYS_VERSION_INFO_QUALIFIED_NAME = QualifiedName.fromDottedString("sys.version_info")
-
- private fun evaluateVersion(versionTuple: PyTupleExpression): Version? {
- val elements = versionTuple.elements
- if (elements.size != 1 && elements.size != 2) {
- return null
- }
-
- val major = evaluateNumber(elements[0])
- if (major == null) {
- return null
- }
-
- if (elements.size == 1) {
- return Version(major, 0, 0)
- }
-
- val minor = evaluateNumber(elements[1])
- if (minor == null) {
- return null
- }
-
- return Version(major, minor, 0)
- }
-
- private fun evaluateNumber(expression: PyExpression?): Int? {
- if (expression !is PyNumericLiteralExpression) return null
- if (!expression.isIntegerLiteral) return null
- val value = expression.bigIntegerValue
- val intValue = value.toInt()
- return if (BigInteger.valueOf(intValue.toLong()) == value) intValue else null
- }
-}
\ No newline at end of file
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyVersionSpecificStubBase.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyVersionSpecificStubBase.kt
index 1e88039ff2c3..3da0c184a333 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyVersionSpecificStubBase.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyVersionSpecificStubBase.kt
@@ -6,9 +6,12 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.*
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
+import com.intellij.psi.util.QualifiedName
+import com.jetbrains.python.PyTokenTypes
import com.jetbrains.python.psi.*
-import com.jetbrains.python.psi.impl.PyVersionCheck
+import com.jetbrains.python.psi.impl.PyPsiUtils
import com.jetbrains.python.psi.stubs.PyVersionSpecificStub
+import java.math.BigInteger
internal abstract class PyVersionSpecificStubBase(
parent: StubElement<*>?,
@@ -49,7 +52,7 @@ internal fun evaluateVersionsForElement(element: PsiElement): ImmutableRangeSet<
private fun evaluateVersionRangeForIfStatementPart(ifStatement: PyIfStatement, ifStatementPart: PsiElement): RangeSet? {
assert(ifStatementPart is PyIfPart || ifStatementPart is PyElsePart)
val result = if (ifStatementPart is PyIfPart) {
- val versionRanges = PyVersionCheck.convertToVersionRanges(ifStatementPart) ?: return null
+ val versionRanges = convertToVersionRanges(ifStatementPart) ?: return null
TreeRangeSet.create(versionRanges)
}
else {
@@ -57,12 +60,88 @@ private fun evaluateVersionRangeForIfStatementPart(ifStatement: PyIfStatement, i
}
val ifParts = sequenceOf(ifStatement.ifPart) + ifStatement.elifParts.asSequence()
for (ifPart in ifParts.takeWhile { it !== ifStatementPart }) {
- val versionRanges = PyVersionCheck.convertToVersionRanges(ifPart) ?: return null
+ val versionRanges = convertToVersionRanges(ifPart) ?: return null
result.removeAll(versionRanges)
}
return result
}
+/**
+ * @return Version ranges if {@code expression} is a version check, {@code null} otherwise
+ *
+ * @see Version and Platform Checks
+ */
+private fun convertToVersionRanges(ifPart: PyIfPart): ImmutableRangeSet? {
+ return ifPart.condition?.let { convertToVersionRanges(it) }
+}
+
+private fun convertToVersionRanges(expression: PyExpression): ImmutableRangeSet? {
+ val binaryExpr = PyPsiUtils.flattenParens(expression) as? PyBinaryExpression ?: return null
+ when (val operator = binaryExpr.operator) {
+ PyTokenTypes.AND_KEYWORD, PyTokenTypes.OR_KEYWORD -> {
+ val rhs = binaryExpr.rightExpression ?: return null
+ val ranges1 = convertToVersionRanges(binaryExpr.leftExpression) ?: return null
+ val ranges2 = convertToVersionRanges(rhs) ?: return null
+ return if (operator === PyTokenTypes.AND_KEYWORD)
+ ranges1.intersection(ranges2)
+ else
+ ranges1.union(ranges2)
+ }
+
+ PyTokenTypes.LT, PyTokenTypes.GT, PyTokenTypes.LE, PyTokenTypes.GE -> {
+ val refExpr = PyPsiUtils.flattenParens(binaryExpr.leftExpression) as? PyReferenceExpression ?: return null
+ if (SYS_VERSION_INFO_QUALIFIED_NAME != refExpr.asQualifiedName()) return null
+
+ val tuple = PyPsiUtils.flattenParens(binaryExpr.rightExpression) as? PyTupleExpression ?: return null
+ val version = evaluateVersion(tuple) ?: return null
+
+ val range = when (operator) {
+ PyTokenTypes.LT -> Range.lessThan(version)
+ PyTokenTypes.GT -> Range.greaterThan(version)
+ PyTokenTypes.LE -> Range.atMost(version)
+ PyTokenTypes.GE -> Range.atLeast(version)
+ else -> throw IllegalStateException()
+ }
+ return ImmutableRangeSet.of(range)
+ }
+
+ else -> return null
+ }
+}
+
+private val SYS_VERSION_INFO_QUALIFIED_NAME = QualifiedName.fromDottedString("sys.version_info")
+
+private fun evaluateVersion(versionTuple: PyTupleExpression): Version? {
+ val elements = versionTuple.elements
+ if (elements.size != 1 && elements.size != 2) {
+ return null
+ }
+
+ val major = evaluateNumber(elements[0])
+ if (major == null) {
+ return null
+ }
+
+ if (elements.size == 1) {
+ return Version(major, 0, 0)
+ }
+
+ val minor = evaluateNumber(elements[1])
+ if (minor == null) {
+ return null
+ }
+
+ return Version(major, minor, 0)
+}
+
+private fun evaluateNumber(expression: PyExpression?): Int? {
+ if (expression !is PyNumericLiteralExpression) return null
+ if (!expression.isIntegerLiteral) return null
+ val value = expression.bigIntegerValue
+ val intValue = value.toInt()
+ return if (BigInteger.valueOf(intValue.toLong()) == value) intValue else null
+}
+
internal fun serializeVersions(versions: RangeSet, outputStream: StubOutputStream) {
val ranges = versions.asRanges()
outputStream.writeVarInt(ranges.size)