mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fixed collecting wrong '__contains__' attribute for structural types
The 'x in y' expression implies that 'y' has the '__contains__' attribute, while our references in qualified expressions tell that the 'x' references the name '__contains__'. In order to fix this we have to treat the operators with a receiver on the right side of the expression differently.
This commit is contained in:
@@ -472,7 +472,7 @@ public class PyNames {
|
||||
}
|
||||
|
||||
public static boolean isRightOperatorName(@Nullable String name) {
|
||||
return name != null && name.matches("__r[a-z]+__");
|
||||
return name != null && (name.matches("__r[a-z]+__") || CONTAINS.equals(name));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -306,11 +306,15 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
|
||||
final PyQualifiedExpression expr = (PyQualifiedExpression)node;
|
||||
final PyExpression qualifier = expr.getQualifier();
|
||||
if (qualifier != null) {
|
||||
final PsiReference ref = qualifier.getReference();
|
||||
if (ref != null && ref.isReferenceTo(PyNamedParameterImpl.this)) {
|
||||
final String attributeName = expr.getReferencedName();
|
||||
if (attributeName != null && !result.contains(attributeName)) {
|
||||
result.add(attributeName);
|
||||
final String attributeName = expr.getReferencedName();
|
||||
final PyExpression referencedExpr = node instanceof PyBinaryExpression && PyNames.isRightOperatorName(attributeName) ?
|
||||
((PyBinaryExpression)node).getRightExpression() : qualifier;
|
||||
if (referencedExpr != null) {
|
||||
final PsiReference ref = referencedExpr.getReference();
|
||||
if (ref != null && ref.isReferenceTo(PyNamedParameterImpl.this)) {
|
||||
if (attributeName != null && !result.contains(attributeName)) {
|
||||
result.add(attributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +473,7 @@ public class PyTypeChecker {
|
||||
}
|
||||
final Callable callable = ((PyFunctionType)type).getCallable();
|
||||
final String operatorName = typedElement.getName();
|
||||
final boolean isRight = PyNames.isRightOperatorName(operatorName) || PyNames.CONTAINS.equals(operatorName);
|
||||
final boolean isRight = PyNames.isRightOperatorName(operatorName);
|
||||
final PyExpression arg = isRight ? expr.getLeftExpression() : expr.getRightExpression();
|
||||
final PyExpression receiver = isRight ? expr.getRightExpression() : expr.getLeftExpression();
|
||||
final PyParameter[] parameters = callable.getParameterList().getParameters();
|
||||
|
||||
@@ -977,6 +977,15 @@ public class PyTypeTest extends PyTestCase {
|
||||
" expr = x\n");
|
||||
}
|
||||
|
||||
public void testNoContainsInContainsArgumentForStructuralType() {
|
||||
doTest("{foo, __getitem__}",
|
||||
"def f(x):\n" +
|
||||
" x in []\n" +
|
||||
" x.foo\n" +
|
||||
" x[0]" +
|
||||
" expr = x\n");
|
||||
}
|
||||
|
||||
private static TypeEvalContext getTypeEvalContext(@NotNull PyExpression element) {
|
||||
return TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user