mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixed unresolved reference for parameters which methods are invoked inside the function body (PY-11541)
We may get stuck in a recursive resolve loop (that results in unresolved references) if we match arguments to parameters for a call where the callee is a reference to the named parameter itself. The loop used to go like this: 1. Get the type of 'foo.bar' in 'foo.bar(foo)' 2. Get the type of 'foo' in 'def f(foo)' 3. Find the structural type for 'foo' 4. Ask nested calls where 'foo' is a parameter 5. Try to match args to params in 'foo.bar(foo)' 6. Resolve 'foo.bar' 7. Get the type of 'foo.bar' in 'foo.bar(foo') 8. Since the 'foo.bar' is evaluating, it's 'null' for preventing recursion 9. So 'foo.bar' resolves to 'null' which is false
This commit is contained in:
@@ -349,11 +349,29 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyNamedParameter getParameterByCallArgument(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class);
|
||||
if (call != null) {
|
||||
final PyArgumentList argumentList = call.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
private PyNamedParameter getParameterByCallArgument(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
final PyArgumentList argumentList = PsiTreeUtil.getParentOfType(element, PyArgumentList.class);
|
||||
if (argumentList != null) {
|
||||
boolean elementIsArgument = false;
|
||||
for (PyExpression argument : argumentList.getArgumentExpressions()) {
|
||||
if (PyPsiUtils.flattenParens(argument) == element) {
|
||||
elementIsArgument = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
final PyCallExpression callExpression = argumentList.getCallExpression();
|
||||
if (elementIsArgument && callExpression != null) {
|
||||
final PyExpression callee = callExpression.getCallee();
|
||||
if (callee instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression calleeReferenceExpr = (PyReferenceExpression)callee;
|
||||
final PyExpression firstQualifier = PyPsiUtils.getFirstQualifier(calleeReferenceExpr);
|
||||
if (firstQualifier != null) {
|
||||
final PsiReference ref = firstQualifier.getReference();
|
||||
if (ref != null && ref.isReferenceTo(this)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
|
||||
final CallArgumentsMapping mapping = argumentList.analyzeCall(resolveContext);
|
||||
for (Map.Entry<PyExpression, PyNamedParameter> entry : mapping.getPlainMappedParams().entrySet()) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
def repl(s):
|
||||
if not isinstance(s, basestring):
|
||||
return s
|
||||
return s.replace(s.replace('a', 'b'), s)
|
||||
+5
@@ -505,6 +505,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-11541
|
||||
public void testBaseStringCheck() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user