mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
PY-21479 Properly resolve references in f-strings inside comprehensions
Namely, choose the correct anchor PSI element for CFG-sensitive local resolve process: not the whole statement that contains the comprehension but rather the closest ancestor result part of the comprehension because if the referenced symbol is defined inside the comprehension, the corresponding vertex will be below the statement in the graph not above it.
This commit is contained in:
@@ -30,9 +30,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.PyStatement;
|
||||
import com.jetbrains.python.psi.PyStringLiteralExpression;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.PyUtil.StringNodeInfo;
|
||||
import com.jetbrains.python.psi.impl.references.PyReferenceImpl;
|
||||
import com.jetbrains.python.psi.resolve.*;
|
||||
@@ -43,6 +41,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.jetbrains.python.psi.PyUtil.as;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
@@ -100,9 +100,22 @@ public class PyDocReference extends PyReferenceImpl {
|
||||
|
||||
@Nullable
|
||||
private PsiElement getScopeControlFlowAnchor(@NotNull PsiLanguageInjectionHost host) {
|
||||
return isInsideFormattedStringNode(host) ? PsiTreeUtil.getParentOfType(host, PyStatement.class) : null;
|
||||
if (isInsideFormattedStringNode(host)) {
|
||||
// Comprehension's result expression is preserved in CFG: this anchor is necessary for flow-sensitive getResultsFromProcessor()
|
||||
final PsiElement parentComprehensionResult = PsiTreeUtil.findFirstParent(host, PyDocReference::isComprehensionResult);
|
||||
if (parentComprehensionResult != null) {
|
||||
return parentComprehensionResult;
|
||||
}
|
||||
return PsiTreeUtil.getParentOfType(host, PyStatement.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isComprehensionResult(@NotNull PsiElement element) {
|
||||
final PyComprehensionElement comprehension = as(element.getParent(), PyComprehensionElement.class);
|
||||
return comprehension != null && comprehension.getResultExpression() == element;
|
||||
}
|
||||
|
||||
private boolean isInsideFormattedStringNode(@NotNull PsiLanguageInjectionHost host) {
|
||||
if (host instanceof PyStringLiteralExpression) {
|
||||
final ASTNode node = findContainingStringNode(getElement(), (PyStringLiteralExpression)host);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
foo = 42
|
||||
xs = [x for x in f'{foo}']
|
||||
<ref>
|
||||
2
python/testData/resolve/FStringComprehensionTarget.py
Normal file
2
python/testData/resolve/FStringComprehensionTarget.py
Normal file
@@ -0,0 +1,2 @@
|
||||
xs = [f'{foo}' + foo for foo in range(10)]
|
||||
<ref>
|
||||
@@ -0,0 +1,2 @@
|
||||
xs = [[x for x in f'{foo}'] for foo in range(10)]
|
||||
<ref>
|
||||
@@ -64,7 +64,22 @@ public class PyInjectionResolveTest extends PyResolveTestCase {
|
||||
public void testFStringNestedScopes() {
|
||||
assertResolvesTo(LanguageLevel.PYTHON36, PyTargetExpression.class, "foo");
|
||||
}
|
||||
|
||||
// PY-21479
|
||||
public void testFStringComprehensionTarget() {
|
||||
assertResolvesTo(LanguageLevel.PYTHON36, PyTargetExpression.class, "foo");
|
||||
}
|
||||
|
||||
// PY-21479
|
||||
public void testFStringComprehensionSourcePart() {
|
||||
assertResolvesTo(LanguageLevel.PYTHON36, PyTargetExpression.class, "foo");
|
||||
}
|
||||
|
||||
// PY-21479
|
||||
public void testFStringNestedComprehensionSourcePart() {
|
||||
assertResolvesTo(LanguageLevel.PYTHON36, PyTargetExpression.class, "foo");
|
||||
}
|
||||
|
||||
public void testTypeCommentReference() {
|
||||
assertResolvesTo(PyClass.class, "MyClass");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user