From c129ddc50644765bb3d045f528db7f413126a2e3 Mon Sep 17 00:00:00 2001 From: Andrey Vokin Date: Wed, 18 Jun 2025 15:17:14 +0200 Subject: [PATCH] PY-81269 Extremely High RAM Usage (cherry picked from commit bb534d62931c176d2395e2cceb0afabc57464669) GitOrigin-RevId: 4a5b1398ca3fc3245d8e497fdd0522971e9fca51 --- .../python/psi/PyInstantTypeProvider.kt | 7 +++ .../python/psi/types/TypeEvalContext.java | 60 +++++++++++++++++-- .../resources/META-INF/PythonPsiImpl.xml | 2 + .../psi/impl/PyBoolLiteralExpressionImpl.java | 3 +- .../psi/impl/PyDoubleStarExpressionImpl.java | 3 +- .../psi/impl/PyDoubleStarPatternImpl.java | 3 +- .../psi/impl/PyEmptyExpressionImpl.java | 3 +- .../psi/impl/PyKeyValuePatternImpl.java | 3 +- .../psi/impl/PyNoneLiteralExpressionImpl.java | 3 +- .../impl/PyNumericLiteralExpressionImpl.java | 3 +- .../python/psi/impl/PyReprExpressionImpl.java | 3 +- .../psi/impl/PySingleStarPatternImpl.java | 2 +- .../python/psi/impl/PyStarArgumentImpl.java | 3 +- .../python/psi/impl/PyStarExpressionImpl.java | 3 +- 14 files changed, 85 insertions(+), 16 deletions(-) create mode 100644 python/python-psi-api/src/com/jetbrains/python/psi/PyInstantTypeProvider.kt diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyInstantTypeProvider.kt b/python/python-psi-api/src/com/jetbrains/python/psi/PyInstantTypeProvider.kt new file mode 100644 index 000000000000..55dcd13b46c4 --- /dev/null +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyInstantTypeProvider.kt @@ -0,0 +1,7 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.psi + +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +interface PyInstantTypeProvider : PyTypedElement \ No newline at end of file diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/python-psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index 50bb740192b2..c5f3fca67505 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -4,13 +4,12 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.RecursionManager; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.ProcessingContext; -import com.jetbrains.python.psi.PyCallable; -import com.jetbrains.python.psi.PyNoneLiteralExpression; -import com.jetbrains.python.psi.PyTypedElement; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyTypeProvider; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -22,7 +21,7 @@ import java.util.List; import java.util.Map; -public final class TypeEvalContext { +public sealed class TypeEvalContext { /** * This class ensures that only {@link TypeEvalContext} instances can directly invoke @@ -97,7 +96,7 @@ public final class TypeEvalContext { * Inspections should not create a new type evaluation context. They should re-use the context of the inspection session. */ public static TypeEvalContext codeAnalysis(final @NotNull Project project, final @Nullable PsiFile origin) { - return getContextFromCache(project, new TypeEvalContext(false, false, false, origin)); + return getContextFromCache(project, buildCodeAnalysisContext(origin)); } /** @@ -124,6 +123,13 @@ public final class TypeEvalContext { return getContextFromCache(project, new TypeEvalContext(false, true, false, null)); } + private static TypeEvalContext buildCodeAnalysisContext(@Nullable PsiFile origin) { + if (Registry.is("python.optimized.type.eval.context")) { + return new OptimizedTypeEvalContext(false, false, false, origin); + } + return new TypeEvalContext(false, false, false, origin); + } + /** * Moves context through cache returning one from cache (if exists). * @@ -283,4 +289,48 @@ public final class TypeEvalContext { return getContextFile(context); } } + + final static class OptimizedTypeEvalContext extends TypeEvalContext { + private volatile TypeEvalContext codeInsightFallback; + + OptimizedTypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, boolean allowCallContext, @Nullable PsiFile origin) { + super(allowDataFlow, allowStubToAST, allowCallContext, origin); + } + + private boolean shouldSwitchToFallbackContext(PsiElement element) { + PsiFile file = element.getContainingFile(); + if (file instanceof PyExpressionCodeFragment codeFragment) { + PsiElement context = codeFragment.getContext(); + if (context != null) { + file = context.getContainingFile(); + } + } + TypeEvalConstraints constraints = getConstraints(); + return constraints.myOrigin != null && file != constraints.myOrigin && (file instanceof PyFile) && + !constraints.myAllowDataFlow && !constraints.myAllowStubToAST && !constraints.myAllowCallContext; + } + + private TypeEvalContext getFallbackContext(Project project) { + if (codeInsightFallback == null) { + codeInsightFallback = codeInsightFallback(project); + } + return codeInsightFallback; + } + + @Override + public @Nullable PyType getType(@NotNull PyTypedElement element) { + if (shouldSwitchToFallbackContext(element)) { + return getFallbackContext(element.getProject()).getType(element); + } + return super.getType(element); + } + + @Override + public @Nullable PyType getReturnType(@NotNull PyCallable callable) { + if (shouldSwitchToFallbackContext(callable)) { + return getFallbackContext(callable.getProject()).getReturnType(callable); + } + return super.getReturnType(callable); + } + } } diff --git a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml index 3e538adbd78e..33764f35547d 100644 --- a/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml +++ b/python/python-psi-impl/resources/META-INF/PythonPsiImpl.xml @@ -477,6 +477,8 @@ description="Require marking namespace packages explicitly, treat regular directories as implicit source roots"/> + diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java index aba98d9bd095..90a6e30d87e4 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java @@ -4,12 +4,13 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyBoolLiteralExpression; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; -public class PyBoolLiteralExpressionImpl extends PyElementImpl implements PyBoolLiteralExpression { +public class PyBoolLiteralExpressionImpl extends PyElementImpl implements PyBoolLiteralExpression, PyInstantTypeProvider { public PyBoolLiteralExpressionImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarExpressionImpl.java index 1299b54a4495..0d22a08c6c03 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarExpressionImpl.java @@ -18,12 +18,13 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyDoubleStarExpression; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyDoubleStarExpressionImpl extends PyElementImpl implements PyDoubleStarExpression { +public class PyDoubleStarExpressionImpl extends PyElementImpl implements PyDoubleStarExpression, PyInstantTypeProvider { public PyDoubleStarExpressionImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarPatternImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarPatternImpl.java index f5c4dfd8e114..64fe3beae3c1 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarPatternImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDoubleStarPatternImpl.java @@ -3,12 +3,13 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyDoubleStarPattern; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyDoubleStarPatternImpl extends PyElementImpl implements PyDoubleStarPattern { +public class PyDoubleStarPatternImpl extends PyElementImpl implements PyDoubleStarPattern, PyInstantTypeProvider { public PyDoubleStarPatternImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java index caaa32c3a687..4247f8ca065c 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java @@ -3,12 +3,13 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyEmptyExpression; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; -public class PyEmptyExpressionImpl extends PyElementImpl implements PyEmptyExpression { +public class PyEmptyExpressionImpl extends PyElementImpl implements PyEmptyExpression, PyInstantTypeProvider { public PyEmptyExpressionImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyKeyValuePatternImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyKeyValuePatternImpl.java index 5bc2c8eb59da..0b22e0cbb48d 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyKeyValuePatternImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyKeyValuePatternImpl.java @@ -2,6 +2,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.PyKeyValuePattern; import com.jetbrains.python.psi.PyPattern; import com.jetbrains.python.psi.types.PyTupleType; @@ -11,7 +12,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; -public class PyKeyValuePatternImpl extends PyElementImpl implements PyKeyValuePattern { +public class PyKeyValuePatternImpl extends PyElementImpl implements PyKeyValuePattern, PyInstantTypeProvider { public PyKeyValuePatternImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java index 1268db5e2b7c..932bd5f8560a 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java @@ -17,6 +17,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.PyNoneLiteralExpression; import com.jetbrains.python.psi.types.PyNoneType; import com.jetbrains.python.psi.types.PyType; @@ -25,7 +26,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyNoneLiteralExpressionImpl extends PyElementImpl implements PyNoneLiteralExpression { +public class PyNoneLiteralExpressionImpl extends PyElementImpl implements PyNoneLiteralExpression, PyInstantTypeProvider { public PyNoneLiteralExpressionImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNumericLiteralExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNumericLiteralExpressionImpl.java index d19ea0df6aa0..33045d245f29 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNumericLiteralExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNumericLiteralExpressionImpl.java @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.tree.IElementType; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.PyNumericLiteralExpression; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -26,7 +27,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyNumericLiteralExpressionImpl extends PyElementImpl implements PyNumericLiteralExpression { +public class PyNumericLiteralExpressionImpl extends PyElementImpl implements PyNumericLiteralExpression, PyInstantTypeProvider { public PyNumericLiteralExpressionImpl(@NotNull ASTNode astNode) { super(astNode); diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyReprExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyReprExpressionImpl.java index 2d45f6e45877..2a70026c86da 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyReprExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyReprExpressionImpl.java @@ -3,13 +3,14 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.PyReprExpression; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; -public class PyReprExpressionImpl extends PyElementImpl implements PyReprExpression { +public class PyReprExpressionImpl extends PyElementImpl implements PyReprExpression, PyInstantTypeProvider { public PyReprExpressionImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PySingleStarPatternImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PySingleStarPatternImpl.java index e50857893a49..9ee3745357d9 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PySingleStarPatternImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PySingleStarPatternImpl.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.List; -public class PySingleStarPatternImpl extends PyElementImpl implements PySingleStarPattern { +public class PySingleStarPatternImpl extends PyElementImpl implements PySingleStarPattern, PyInstantTypeProvider { public PySingleStarPatternImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarArgumentImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarArgumentImpl.java index 4bb074b783e8..f7d08405d2cd 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarArgumentImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarArgumentImpl.java @@ -2,13 +2,14 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.PyStarArgument; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; -public class PyStarArgumentImpl extends PyElementImpl implements PyStarArgument { +public class PyStarArgumentImpl extends PyElementImpl implements PyStarArgument, PyInstantTypeProvider { public PyStarArgumentImpl(ASTNode astNode) { super(astNode); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java index a60e67285c2b..86a04efaabf3 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java @@ -3,12 +3,13 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.jetbrains.python.psi.PyElementVisitor; +import com.jetbrains.python.psi.PyInstantTypeProvider; import com.jetbrains.python.psi.PyStarExpression; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; -public class PyStarExpressionImpl extends PyElementImpl implements PyStarExpression { +public class PyStarExpressionImpl extends PyElementImpl implements PyStarExpression, PyInstantTypeProvider { public PyStarExpressionImpl(ASTNode astNode) { super(astNode); }