PY-25045 Fixed: False positive: expected type '{__div__}', got 'Union[int, float]' instead

Update PyBinaryExpressionImpl to return `__truediv__` as referenced name instead of `__div__` when it is enabled.
This commit is contained in:
Semyon Proshev
2017-07-17 16:41:11 +03:00
parent 09078b7778
commit a361fee76e
6 changed files with 30 additions and 16 deletions
@@ -17,6 +17,7 @@ package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
@@ -24,6 +25,7 @@ import com.intellij.psi.util.QualifiedName;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.references.PyOperatorReference;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -209,6 +211,9 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp
@Override
public String getReferencedName() {
final PyElementType t = getOperator();
if (t == PyTokenTypes.DIV && isTrueDivEnabled(this)) {
return PyNames.TRUEDIV;
}
return t != null ? t.getSpecialMethodName() : null;
}
@@ -217,4 +222,13 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp
final PsiElement op = getPsiOperator();
return op != null ? op.getNode() : null;
}
private static boolean isTrueDivEnabled(@NotNull PyElement anchor) {
final PsiFile file = anchor.getContainingFile();
if (file instanceof PyFile) {
final PyFile pyFile = (PyFile)file;
return FutureFeature.DIVISION.requiredAt(pyFile.getLanguageLevel()) || pyFile.hasImportFromFuture(FutureFeature.DIVISION);
}
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@ package com.jetbrains.python.psi.impl.references;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
@@ -54,9 +53,6 @@ public class PyOperatorReference extends PyReferenceImpl {
res = resolveMember(expr.getRightExpression(), name);
}
else {
if (PyNames.DIV.equals(name) && isTrueDivEnabled(myElement)) {
resolveLeftAndRightOperators(res, expr, PyNames.TRUEDIV);
}
resolveLeftAndRightOperators(res, expr, name);
}
}
@@ -125,15 +121,6 @@ public class PyOperatorReference extends PyReferenceImpl {
return name.replaceFirst("__([a-z]+)__", "__r$1__");
}
private static boolean isTrueDivEnabled(@NotNull PyElement anchor) {
final PsiFile file = anchor.getContainingFile();
if (file instanceof PyFile) {
final PyFile pyFile = (PyFile)file;
return FutureFeature.DIVISION.requiredAt(pyFile.getLanguageLevel()) || pyFile.hasImportFromFuture(FutureFeature.DIVISION);
}
return false;
}
private void resolveLeftAndRightOperators(List<RatedResolveResult> res, PyBinaryExpression expr, String name) {
final TypeEvalContext typeEvalContext = myContext.getTypeEvalContext();
typeEvalContext.trace("Trying to resolve left operator");
@@ -0,0 +1,8 @@
from typing import Union
def foo(x):
return x / (60 * 60)
bar = 0 # type: Union[int, float]
foo(bar)
@@ -1,5 +1,5 @@
class D1(object):
def __div__(self, other) -> "D1": ...
def __truediv__(self, other) -> "D1": ...
class D2(object):
def __rtruediv__(self, other) -> "D2": ...
@@ -483,7 +483,7 @@ public class Py3TypeTest extends PyTestCase {
public void testNumpyResolveRaterDoesNotIncreaseRateForNotNdarrayRightOperatorFoundInStub() {
myFixture.copyDirectoryToProject(TEST_DIRECTORY + getTestName(false), "");
doTest("Union[D2, D1]",
doTest("Union[D1, D2]",
"class D1(object):\n" +
" pass\n" +
"class D2(object):\n" +
@@ -255,4 +255,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase {
public void testPromotingBytearrayToBytes() {
doTest();
}
// PY-25045
public void testUnionOfIntAndFloatShouldBeConsideredAsDividable() {
doTest();
}
}