Update PyCompatibilityInspection to correctly process long in Python 2.

The reason of update is that `long` is described as `long = int` in pyi-stubs.
This commit is contained in:
Semyon Proshev
2017-06-20 11:36:46 +03:00
parent 302caea766
commit c4c6294e1d
8 changed files with 41 additions and 20 deletions
@@ -38,6 +38,7 @@ public class PyNames {
* int type
*/
public static final String TYPE_INT = "int";
public static final String TYPE_LONG = "long";
/**
* unicode string type (see {@link #TYPE_STRING_TYPES}
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 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.
@@ -33,7 +33,6 @@ import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
@@ -72,6 +71,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase<PsiEleme
return null;
}
@Override
public boolean isSoft() {
return false;
}
@@ -125,9 +125,9 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase<PsiEleme
@NotNull
public List<Object> collectTypeVariants() {
final PsiFile file = myElement.getContainingFile();
final ArrayList<Object>
variants = Lists.newArrayList("str", "int", "basestring", "bool", "buffer", "bytearray", "complex", "dict",
"tuple", "enumerate", "file", "float", "frozenset", "list", "long", "set", "object");
final List<Object> variants =
Lists.newArrayList(PyNames.TYPE_STR, PyNames.TYPE_INT, "basestring", "bool", "buffer", "bytearray", "complex", "dict",
"tuple", "enumerate", "file", "float", "frozenset", "list", PyNames.TYPE_LONG, "set", "object");
if (file instanceof PyFile) {
variants.addAll(((PyFile)file).getTopLevelClasses());
final List<PyFromImportStatement> fromImports = ((PyFile)file).getFromImports();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 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.
@@ -169,15 +169,14 @@ public class PyCompatibilityInspection extends PyInspection {
public void visitPyCallExpression(PyCallExpression node) {
super.visitPyCallExpression(node);
final Optional<PyFunction> optionalFunction = Optional
final PsiElement resolvedCallee = Optional
.ofNullable(node.getCallee())
.map(PyExpression::getReference)
.map(PsiReference::resolve)
.filter(PyFunction.class::isInstance)
.map(PyFunction.class::cast);
.orElse(null);
if (optionalFunction.isPresent()) {
final PyFunction function = optionalFunction.get();
if (resolvedCallee instanceof PyFunction) {
final PyFunction function = (PyFunction)resolvedCallee;
final PyClass containingClass = function.getContainingClass();
final String originalFunctionName = function.getName();
@@ -208,6 +207,18 @@ public class PyCompatibilityInspection extends PyInspection {
null);
}
}
else if (resolvedCallee instanceof PyTargetExpression) {
final PyTargetExpression target = (PyTargetExpression)resolvedCallee;
if (!target.isQualified() &&
PyNames.TYPE_LONG.equals(target.getName()) &&
PyBuiltinCache.getInstance(resolvedCallee).isBuiltin(resolvedCallee)) {
registerForAllMatchingVersions(level -> UnsupportedFeaturesUtil.BUILTINS.get(level).contains(PyNames.TYPE_LONG),
" not have type long. Use int instead.",
node,
null);
}
}
}
@Override
@@ -448,8 +448,12 @@ public class PyStringFormatInspection extends PyInspection {
}
private static class NewStyleInspection {
private static final List<String> CHECKED_TYPES = Arrays.asList("str", "int", "long", "float", "complex", "None");
private static final List<String> NUMERIC_TYPES = Arrays.asList("int", "long", "float", "complex");
private static final List<String> CHECKED_TYPES =
Arrays.asList(PyNames.TYPE_STR, PyNames.TYPE_INT, PyNames.TYPE_LONG, "float", "complex", "None");
private static final List<String> NUMERIC_TYPES = Arrays.asList(PyNames.TYPE_INT, PyNames.TYPE_LONG, "float", "complex");
private static final ImmutableMap<Character, String> NEW_STYLE_FORMAT_CONVERSIONS = ImmutableMap.<Character, String>builder()
.put('s', "str or None")
.put('b', "int")
@@ -347,14 +347,14 @@ public class PyTypeChecker {
final String superName = expected.getName();
final String subName = actual.getName();
final boolean subIsBool = "bool".equals(subName);
final boolean subIsInt = "int".equals(subName);
final boolean subIsLong = "long".equals(subName);
final boolean subIsInt = PyNames.TYPE_INT.equals(subName);
final boolean subIsLong = PyNames.TYPE_LONG.equals(subName);
final boolean subIsFloat = "float".equals(subName);
final boolean subIsComplex = "complex".equals(subName);
if (superName == null || subName == null ||
superName.equals(subName) ||
("int".equals(superName) && subIsBool) ||
(("long".equals(superName) || PyNames.ABC_INTEGRAL.equals(superName)) && (subIsBool || subIsInt)) ||
(PyNames.TYPE_INT.equals(superName) && subIsBool) ||
((PyNames.TYPE_LONG.equals(superName) || PyNames.ABC_INTEGRAL.equals(superName)) && (subIsBool || subIsInt)) ||
(("float".equals(superName) || PyNames.ABC_REAL.equals(superName)) && (subIsBool || subIsInt || subIsLong)) ||
(("complex".equals(superName) || PyNames.ABC_COMPLEX.equals(superName)) && (subIsBool || subIsInt || subIsLong || subIsFloat)) ||
(PyNames.ABC_NUMBER.equals(superName) && (subIsBool || subIsInt || subIsLong || subIsFloat || subIsComplex))) {
@@ -500,7 +500,7 @@ public class PyTypeParser {
else if (PyNames.NONE.equals(name)) {
return new ParseResult(PyNoneType.INSTANCE, range);
}
else if ("integer".equals(name) || "long".equals(name)) {
else if ("integer".equals(name) || PyNames.TYPE_LONG.equals(name)) {
final PyClassType type = builtinCache.getIntType();
return type != null ? new ParseResult(type, range) : EMPTY_RESULT;
}
@@ -516,7 +516,7 @@ public class PyTypeParser {
final PyClassType type = builtinCache.getBytesType(LanguageLevel.forElement(myAnchor));
return type != null ? new ParseResult(type, range) : EMPTY_RESULT;
}
else if ("unicode".equals(name)) {
else if (PyNames.TYPE_UNICODE.equals(name)) {
final PyClassType type = builtinCache.getUnicodeType(LanguageLevel.forElement(myAnchor));
return type != null ? new ParseResult(type, range) : EMPTY_RESULT;
}
@@ -0,0 +1 @@
<warning descr="Python version 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 do not have type long. Use int instead.">long("abc")</warning>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 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.
@@ -229,6 +229,10 @@ public class PyCompatibilityInspectionTest extends PyTestCase {
doTest();
}
public void testBuiltinLong() {
doTest();
}
private void doTest(@NotNull LanguageLevel level) {
runWithLanguageLevel(level, this::doTest);
}