mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 21:41:24 +07:00
PY-77168 Allow flow-sensitive resolve from unmatched version checks to reachable outer blocks
Also, don't query LanguageLevel for each element of each instruction,
only once per scope traversal.
This doesn't fix the problem with unreachable definition *inside* blocks under
unmatched version checks, i.e.
if sys.version_info < (3, 8):
Alias = int
expr: Alias # unresolved
but it's a more difficult problem how to handle those consistently with the idea
of unreachable version checks under the *current* interpreter version, and hopefully
it occurs rarer than, say, unresolved top-level imports of common names from typing.
(cherry picked from commit 55fd4597c6d0860d290caba15fbf4d313e985a86)
IJ-CR-149696
GitOrigin-RevId: 357ada7e10618aef75c470e6cd878f7672109e83
This commit is contained in:
committed by
intellij-monorepo-bot
parent
22cae80f9d
commit
535af53f05
@@ -2137,6 +2137,18 @@ public abstract class PyCommonResolveTest extends PyCommonResolveTestCase {
|
||||
assertResolvedElement(LanguageLevel.PYTHON34, starImport, TestCase::assertNull);
|
||||
}
|
||||
|
||||
// PY-77168
|
||||
public void testResolveFromUnderUnmatchedVersionCheck() {
|
||||
assertResolvesTo("""
|
||||
import sys
|
||||
|
||||
Alias = int
|
||||
if sys.version_info < (3, 12):
|
||||
name: Alias
|
||||
# <ref>
|
||||
""", PyTargetExpression.class, "Alias");
|
||||
}
|
||||
|
||||
private void assertResolvedElement(@NotNull LanguageLevel languageLevel, @NotNull String text, @NotNull Consumer<PsiElement> assertion) {
|
||||
runWithLanguageLevel(languageLevel, () -> {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
|
||||
@@ -86,9 +86,6 @@ public final class PyDefUseUtil {
|
||||
final HashMap<PyCallSiteExpression, ConditionalInstruction> pendingTypeGuard = new HashMap<>();
|
||||
ControlFlowUtil.iteratePrev(startNum, instructions,
|
||||
instruction -> {
|
||||
if (unreachableDueToVersionGuard(instruction)) {
|
||||
return ControlFlowUtil.Operation.CONTINUE;
|
||||
}
|
||||
if (acceptTypeAssertions && instruction instanceof CallInstruction callInstruction) {
|
||||
var typeGuardInstruction = pendingTypeGuard.get(instruction.getElement());
|
||||
if (typeGuardInstruction != null) {
|
||||
@@ -123,14 +120,18 @@ public final class PyDefUseUtil {
|
||||
if (access.isWriteAccess() || acceptTypeAssertions && access.isAssertTypeAccess()) {
|
||||
final String name = elementName(element);
|
||||
if (Comparing.strEqual(name, varName)) {
|
||||
result.add(rwInstruction);
|
||||
if (isReachableWithVersionChecks(rwInstruction)) {
|
||||
result.add(rwInstruction);
|
||||
}
|
||||
return ControlFlowUtil.Operation.CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (acceptImplicitImports && element instanceof PyImplicitImportNameDefiner implicit) {
|
||||
if (!implicit.multiResolveName(varName).isEmpty()) {
|
||||
result.add(instruction);
|
||||
if (isReachableWithVersionChecks(instruction)) {
|
||||
result.add(instruction);
|
||||
}
|
||||
return ControlFlowUtil.Operation.CONTINUE;
|
||||
}
|
||||
}
|
||||
@@ -139,12 +140,12 @@ public final class PyDefUseUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean unreachableDueToVersionGuard(@NotNull Instruction instruction) {
|
||||
private static boolean isReachableWithVersionChecks(@NotNull Instruction instruction) {
|
||||
PsiElement element = instruction.getElement();
|
||||
if (element == null) return false;
|
||||
if (element == null) return true;
|
||||
LanguageLevel languageLevel = PythonLanguageLevelPusher.getLanguageLevelForFile(element.getContainingFile());
|
||||
Version version = new Version(languageLevel.getMajorVersion(), languageLevel.getMinorVersion(), 0);
|
||||
return !evaluateVersionsForElement(element).contains(version);
|
||||
return evaluateVersionsForElement(element).contains(version);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -5959,6 +5959,28 @@ public class PyTypingTest extends PyTestCase {
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-77168
|
||||
public void testReferencingImportedTypeFromUnmatchedVersionGuard() {
|
||||
doTest("Literal[42]", """
|
||||
from typing import Literal
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
expr: Literal[42]
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-77168
|
||||
public void testReferencingTopLevelTypeFromUnmatchedVersionGuard() {
|
||||
doTest("int", """
|
||||
import sys
|
||||
|
||||
type Alias = int
|
||||
if sys.version_info < (3, 0):
|
||||
expr: Alias
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-76243
|
||||
public void testGenericClassDeclaredInStubPackage() {
|
||||
runWithAdditionalClassEntryInSdkRoots("types/" + getTestName(false) + "/site-packages", () -> {
|
||||
|
||||
@@ -341,4 +341,18 @@ public class Py3UnresolvedReferencesInspectionTest extends PyInspectionTestCase
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-77168
|
||||
public void testReferenceFromUnderUnmatchedVersionCheck() {
|
||||
doTestByText("""
|
||||
import sys
|
||||
from typing import overload
|
||||
|
||||
Alias = int
|
||||
if sys.version_info < (3, 12):
|
||||
@overload
|
||||
def f() -> Alias:
|
||||
...
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user