PY-49697 Fix false positive for metaclass overloaded __or__

(cherry picked from commit d8e327da30c0b359c8eb3b890c72c41a9c3c4444)

IJ-MR-11817

GitOrigin-RevId: a21ecb8b66e3510abc4401ac351789a858482463
This commit is contained in:
andrey.matveev
2021-07-13 15:52:04 +07:00
committed by intellij-monorepo-bot
parent 059867630f
commit f84e2d8452
4 changed files with 60 additions and 2 deletions

View File

@@ -28,8 +28,13 @@ import com.jetbrains.python.codeInsight.imports.AddImportHelper;
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
import com.jetbrains.python.inspections.quickfix.*;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyUnionType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -729,6 +734,7 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
private void checkBitwiseOrUnionSyntax(@NotNull PyBinaryExpression node) {
if (node.getOperator() != PyTokenTypes.OR) return;
final PsiFile file = node.getContainingFile();
if (file == null ||
file instanceof PyFile &&
@@ -737,10 +743,21 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
return;
}
final TypeEvalContext context = TypeEvalContext.codeAnalysis(node.getProject(), node.getContainingFile());
final List<PsiElement> resolvedVariants = PyUtil.multiResolveTopPriority(node.getReference(PyResolveContext.defaultContext(context)));
for (PsiElement resolved : resolvedVariants) {
if (resolved instanceof PyFunction) {
final PyClass containingClass = ((PyFunction)resolved).getContainingClass();
if (containingClass == null) return;
final String classQualifiedName = containingClass.getQualifiedName();
if (!PyNames.TYPE.equals(classQualifiedName) && !"types.Union".equals(classQualifiedName)) return;
}
}
// Consider only full expression not parts to have only one registered problem
if (PsiTreeUtil.getParentOfType(node, PyBinaryExpression.class, true, PyStatement.class) != null) return;
final TypeEvalContext context = TypeEvalContext.codeAnalysis(node.getProject(), node.getContainingFile());
final Ref<PyType> refType = PyTypingTypeProvider.getType(node, context);
if (refType != null && refType.get() instanceof PyUnionType) {
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON310),

View File

@@ -0,0 +1,14 @@
class MetaA(type):
def __or__(self, other):
return 42
class A(metaclass=MetaA):
pass
class B:
pass
print(A | B)

View File

@@ -0,0 +1,17 @@
import types
class MetaA(type):
def __or__(self, other) -> types.Union:
return types.Union()
class A(metaclass=MetaA):
pass
class B:
pass
print(A | B)

View File

@@ -518,6 +518,16 @@ public class PythonHighlightingTest extends PyTestCase {
doTest(LanguageLevel.PYTHON39, false, false);
}
// PY-49697
public void testNoErrorMetaClassOverloadBitwiseOrOperator() {
doTest(LanguageLevel.PYTHON39, false, false);
}
// PY-49697
public void testNoErrorMetaClassOverloadBitwiseOrOperatorReturnTypesUnion() {
doTest(LanguageLevel.PYTHON39, false, false);
}
@NotNull
private static EditorColorsScheme createTemporaryColorScheme() {
EditorColorsManager manager = EditorColorsManager.getInstance();