mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
continue name search in upper scopes if the name found in current scope is defined in a comprehension scope and not actually visible from the reference location (PY-8725)
This commit is contained in:
@@ -144,9 +144,8 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ResolveResultList resolveToLatestDefs(@NotNull ScopeOwner owner, @NotNull PsiElement element, @NotNull String name) {
|
||||
private static ResolveResultList resolveToLatestDefs(@NotNull List<ReadWriteInstruction> instructions, @NotNull PsiElement element, @NotNull String name) {
|
||||
final ResolveResultList ret = new ResolveResultList();
|
||||
final List<ReadWriteInstruction> instructions = PyDefUseUtil.getLatestDefs(owner, name, element, false);
|
||||
for (ReadWriteInstruction instruction : instructions) {
|
||||
PsiElement definition = instruction.getElement();
|
||||
NameDefiner definer = null;
|
||||
@@ -191,19 +190,27 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
|
||||
private static boolean isInnerComprehension(PsiElement referenceElement, PsiElement definition) {
|
||||
final PyComprehensionElement definitionComprehension = PsiTreeUtil.getParentOfType(definition, PyComprehensionElement.class);
|
||||
if (definitionComprehension != null) {
|
||||
final boolean isAtLeast30 = LanguageLevel.forElement(definitionComprehension).isAtLeast(LanguageLevel.PYTHON30);
|
||||
final boolean isListComprehension = definitionComprehension instanceof PyListCompExpression;
|
||||
if (!isListComprehension || isAtLeast30) {
|
||||
final PyComprehensionElement elementComprehension = PsiTreeUtil.getParentOfType(referenceElement, PyComprehensionElement.class);
|
||||
if (elementComprehension == null || !PsiTreeUtil.isAncestor(definitionComprehension, elementComprehension, false)) {
|
||||
return true;
|
||||
}
|
||||
if (definitionComprehension != null && isOwnScopeComprehension(definitionComprehension)) {
|
||||
final PyComprehensionElement elementComprehension = PsiTreeUtil.getParentOfType(referenceElement, PyComprehensionElement.class);
|
||||
if (elementComprehension == null || !PsiTreeUtil.isAncestor(definitionComprehension, elementComprehension, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isOwnScopeComprehension(PsiElement definitionComprehension) {
|
||||
final boolean isAtLeast30 = LanguageLevel.forElement(definitionComprehension).isAtLeast(LanguageLevel.PYTHON30);
|
||||
final boolean isListComprehension = definitionComprehension instanceof PyListCompExpression;
|
||||
return !isListComprehension || isAtLeast30;
|
||||
}
|
||||
|
||||
private static boolean isInOwnScopeComprehension(PsiElement uexpr) {
|
||||
PyComprehensionElement comprehensionElement = PsiTreeUtil.getParentOfType(uexpr, PyComprehensionElement.class);
|
||||
return comprehensionElement != null && isOwnScopeComprehension(comprehensionElement);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does actual resolution of resolve().
|
||||
*
|
||||
@@ -251,15 +258,16 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
uexpr = null;
|
||||
}
|
||||
else if (owner == originalOwner && !scope.isGlobal(referencedName)) {
|
||||
final ResolveResultList latest = resolveToLatestDefs(owner, myElement, referencedName);
|
||||
final List<ReadWriteInstruction> instructions = PyDefUseUtil.getLatestDefs(owner, referencedName, myElement, false);
|
||||
final ResolveResultList latest = resolveToLatestDefs(instructions, myElement, referencedName);
|
||||
if (!latest.isEmpty()) {
|
||||
return latest;
|
||||
}
|
||||
if (owner instanceof PyClass) {
|
||||
final ScopeOwner classOwner = ScopeUtil.getScopeOwner(owner);
|
||||
if (classOwner != null) {
|
||||
if (owner instanceof PyClass || (instructions.isEmpty() && isInOwnScopeComprehension(uexpr))) {
|
||||
final ScopeOwner parentOwner = ScopeUtil.getScopeOwner(owner);
|
||||
if (parentOwner != null) {
|
||||
processor = new ResolveProcessor(referencedName);
|
||||
PyResolveUtil.scopeCrawlUp(processor, classOwner, referencedName, roof);
|
||||
PyResolveUtil.scopeCrawlUp(processor, parentOwner, referencedName, roof);
|
||||
uexpr = processor.getResult();
|
||||
}
|
||||
}
|
||||
|
||||
9
python/testData/resolve/GeneratorShadowing.py
Normal file
9
python/testData/resolve/GeneratorShadowing.py
Normal file
@@ -0,0 +1,9 @@
|
||||
def _(arg):
|
||||
print(arg)
|
||||
|
||||
def foo():
|
||||
_("foo") # This call is underlined by the inspector as an unresolved reference
|
||||
# <ref>
|
||||
print("\n".join("bar" for _ in range(5)))
|
||||
|
||||
foo()
|
||||
@@ -521,4 +521,8 @@ public class PyResolveTest extends PyResolveTestCase {
|
||||
assertEquals("foo", res.getName());
|
||||
assertInstanceOf(res.getParent(), PyAugAssignmentStatement.class);
|
||||
}
|
||||
|
||||
public void testGeneratorShadowing() { // PY-8725
|
||||
assertResolvesTo(PyFunction.class, "_");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user