PY-50642 Don't build stubs for elements in unreachable if-branches

GitOrigin-RevId: 2fd1fb6777d80f436a495ff5eca08249bab9d21a
This commit is contained in:
Petr
2025-11-28 19:07:18 +00:00
committed by intellij-monorepo-bot
parent fa138bf032
commit 87e2e9f316
5 changed files with 54 additions and 8 deletions
@@ -60,7 +60,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
@Override
public int getStubVersion() {
// Don't forget to update versions of indexes that use the updated stub-based elements
return 104;
return 105;
}
@Override
@@ -20,9 +20,9 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.stubs.DefaultStubBuilder;
import com.intellij.psi.stubs.StubElement;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyIfStatement;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyEvaluator;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
@@ -38,7 +38,36 @@ public class PyFileStubBuilder extends DefaultStubBuilder {
@Override
public boolean skipChildProcessingWhenBuildingStubs(@NotNull ASTNode parent, @NotNull ASTNode node) {
PsiElement psi = parent.getPsi();
return psi instanceof PyIfStatement && PyUtil.isIfNameEqualsMain((PyIfStatement)psi);
PsiElement parentPsi = parent.getPsi();
if (parentPsi instanceof PyIfStatement && PyUtil.isIfNameEqualsMain((PyIfStatement)parentPsi)) {
return true;
}
if (parentPsi instanceof PyIfStatement ifStatement && node.getPsi() instanceof PyStatementPart part) {
return isAlwaysUnreachable(ifStatement, part);
}
return false;
}
private static boolean isAlwaysUnreachable(@NotNull PyIfStatement ifStatement, @NotNull PyStatementPart part) {
assert part.getParent() == ifStatement;
for (PyIfPart ifPart : StreamEx.of(ifStatement.getIfPart()).append(ifStatement.getElifParts())) {
if (ifPart == part) {
break;
}
Boolean result = PyEvaluator.evaluateAsBooleanNoResolve(ifPart.getCondition());
if (result == Boolean.TRUE) {
return true;
}
}
if (part instanceof PyIfPart ifPart) {
Boolean result = PyEvaluator.evaluateAsBooleanNoResolve(ifPart.getCondition());
if (result == Boolean.FALSE) {
return true;
}
}
return false;
}
}
@@ -1,4 +1,4 @@
if True:
if input():
foo = 42
else:
foo = None
@@ -1,4 +1,4 @@
if True:
if input():
foo = 42
else:
foo = 'spam'
@@ -3348,6 +3348,23 @@ public class Py3TypeTest extends PyTestCase {
""");
}
// PY-50642
public void testTypeCheckingMultiFile() {
myFixture.addFileToProject("mod.py", """
import typing
if not not typing.TYPE_CHECKING:
v: int = -1
else:
v: str = 'ab'
""");
doTest("int", """
from mod import v
expr = v
""");
}
// PY-73958
public void testNoStackOverflow() {
doTest("Foo", """