mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -43,7 +43,8 @@ setProperty("pluginFilter", [
|
||||
"python-uml", "localization",
|
||||
"python-localization",
|
||||
"rest", "python-rest",
|
||||
"pycharm-flask"
|
||||
"pycharm-flask",
|
||||
"pycharm-numpy"
|
||||
])
|
||||
|
||||
private List<String> pycharmPlatformApiModules() {
|
||||
@@ -219,6 +220,7 @@ private layoutPlugins() {
|
||||
layouts.layoutPlugin("rest")
|
||||
layouts.layoutPlugin("python-rest")
|
||||
layouts.layoutPlugin("pycharm-flask")
|
||||
layouts.layoutPlugin("pycharm-numpy")
|
||||
}
|
||||
|
||||
layouts.layoutPlugins()
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<orderEntry type="module" module-name="python-localization" />
|
||||
<orderEntry type="module" module-name="python-rest" />
|
||||
<orderEntry type="module" module-name="pycharm-flask" />
|
||||
<orderEntry type="module" module-name="pycharm-numpy" />
|
||||
<orderEntry type="module" module-name="python-helpers" />
|
||||
<orderEntry type="module" module-name="sql" />
|
||||
</component>
|
||||
|
||||
@@ -50,7 +50,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PyType getParameterType(final PyNamedParameter param, final PyFunction func, TypeEvalContext context) {
|
||||
public PyType getParameterType(@NotNull final PyNamedParameter param, @NotNull final PyFunction func, @NotNull TypeEvalContext context) {
|
||||
if (!(param.getParent() instanceof PyParameterList)) return null;
|
||||
List<PyNamedParameter> params = ParamHelper.collectNamedParameters((PyParameterList) param.getParent());
|
||||
final int index = params.indexOf(param);
|
||||
|
||||
@@ -80,6 +80,11 @@ public class PyNames {
|
||||
public static final String SEQUENCE = "Sequence";
|
||||
public static final String MAPPING = "Mapping";
|
||||
|
||||
public static final String COMPLEX = "Complex";
|
||||
public static final String REAL = "Real";
|
||||
public static final String RATIONAL = "Rational";
|
||||
public static final String INTEGRAL = "Integral";
|
||||
|
||||
public static final String CONTAINS = "__contains__";
|
||||
public static final String HASH = "__hash__";
|
||||
public static final String ITER = "__iter__";
|
||||
@@ -328,7 +333,7 @@ public class PyNames {
|
||||
);
|
||||
|
||||
public static Set<String> BuiltinInterfaces = ImmutableSet.of(
|
||||
CALLABLE, HASHABLE, ITERABLE, ITERATOR, SIZED, CONTAINER, SEQUENCE, MAPPING
|
||||
CALLABLE, HASHABLE, ITERABLE, ITERATOR, SIZED, CONTAINER, SEQUENCE, MAPPING, COMPLEX, REAL, RATIONAL, INTEGRAL
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,12 @@ import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
|
||||
import com.jetbrains.python.psi.types.PyClassType;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -24,8 +27,18 @@ public abstract class PyPsiFacade {
|
||||
@Nullable
|
||||
public abstract PyClass findClass(String qName);
|
||||
|
||||
@NotNull
|
||||
public abstract PyClassType createClassType(@NotNull PyClass pyClass, boolean isDefinition);
|
||||
|
||||
@Nullable
|
||||
public abstract String findShortestImportableName(PsiElement importer, VirtualFile targetFile);
|
||||
public abstract PyType createUnionType(@NotNull Collection<PyType> members);
|
||||
|
||||
@Nullable
|
||||
public abstract PyType createTupleType(@NotNull Collection<PyType> members, @NotNull PsiElement anchor);
|
||||
|
||||
@Nullable
|
||||
public abstract PyType parseTypeAnnotation(@NotNull String annotation, @NotNull PsiElement anchor);
|
||||
|
||||
@Nullable
|
||||
public abstract String findShortestImportableName(@NotNull VirtualFile targetFile, @NotNull PsiElement anchor);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ public interface PyTypeProvider {
|
||||
PyType getReferenceType(@NotNull PsiElement referenceTarget, TypeEvalContext context, @Nullable PsiElement anchor);
|
||||
|
||||
@Nullable
|
||||
PyType getParameterType(PyNamedParameter param, final PyFunction func, TypeEvalContext context);
|
||||
PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context);
|
||||
|
||||
@Nullable
|
||||
PyType getReturnType(PyFunction function, @Nullable PyQualifiedExpression callSite, TypeEvalContext context);
|
||||
PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context);
|
||||
|
||||
@Nullable
|
||||
PyType getIterationType(PyClass iterable);
|
||||
|
||||
@@ -21,7 +21,7 @@ public abstract class PyModuleMembersProvider {
|
||||
public Collection<PyDynamicMember> getMembers(PyFile module, PointInImport point) {
|
||||
final VirtualFile vFile = module.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
final String qName = PyPsiFacade.getInstance(module.getProject()).findShortestImportableName(module, vFile);
|
||||
final String qName = PyPsiFacade.getInstance(module.getProject()).findShortestImportableName(vFile, module);
|
||||
if (qName != null) {
|
||||
return getMembersByQName(module, qName);
|
||||
}
|
||||
|
||||
@@ -75,12 +75,12 @@ public class PyTypeProviderBase implements PyTypeProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PyType getParameterType(PyNamedParameter param, PyFunction func, TypeEvalContext context) {
|
||||
public PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PyType getReturnType(PyFunction function, @Nullable PyQualifiedExpression callSite, TypeEvalContext context) {
|
||||
public PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context) {
|
||||
ReturnTypeDescriptor descriptor;
|
||||
synchronized (myMethodToReturnTypeMap) {
|
||||
descriptor = myMethodToReturnTypeMap.get(function.getName());
|
||||
|
||||
@@ -104,7 +104,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PyType getParameterType(PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) {
|
||||
public PyType getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) {
|
||||
final String name = param.getName();
|
||||
final String qname = getQualifiedName(func, param);
|
||||
if (qname != null && name != null) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
## 2. Built-in functions
|
||||
|
||||
__builtin__.abs = \
|
||||
:type number: int or long or float or complex \n\
|
||||
:rtype: int \n\
|
||||
|
||||
__builtin__.all = \
|
||||
@@ -1577,72 +1576,72 @@ collections.Iterator.next = \
|
||||
## 9.2 math
|
||||
|
||||
math.acos = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.acosh = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.asin = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.asinh = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.atan = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.atan2 = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.atanh = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.ceil = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.copysign = \
|
||||
:type x: int or long or float \n\
|
||||
:type y: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:type y: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.cos = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.cosh = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.degrees = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.erf = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.erfc = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.exp = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.expm1 = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.fabs = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.factorial = \
|
||||
@@ -1650,16 +1649,16 @@ math.factorial = \
|
||||
:rtype: int \n\
|
||||
|
||||
math.floor = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.fmod = \
|
||||
:type x: int or long or float \n\
|
||||
:type y: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:type y: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.frexp = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: (float, int) \n\
|
||||
|
||||
math.fsum = \
|
||||
@@ -1667,79 +1666,79 @@ math.fsum = \
|
||||
:rtype: float \n\
|
||||
|
||||
math.gamma = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.hypot = \
|
||||
:type x: int or long or float \n\
|
||||
:type y: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:type y: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.isinf = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: bool \n\
|
||||
|
||||
math.isnan = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: bool \n\
|
||||
|
||||
math.ldexp = \
|
||||
:type x: int or long or float \n\
|
||||
:type y: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:type y: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.lgamma = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.log = \
|
||||
:type x: int or long or float \n\
|
||||
:type base: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:type base: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.log10 = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.log1p = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.modf = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: (float, float) \n\
|
||||
|
||||
math.pow = \
|
||||
:type x: int or long or float \n\
|
||||
:type y: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:type y: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.radians = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.sin = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.sinh = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.sqrt = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.tan = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.tanh = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: float \n\
|
||||
|
||||
math.trunc = \
|
||||
:type x: int or long or float \n\
|
||||
:type x: float or numbers.Real \n\
|
||||
:rtype: int \n\
|
||||
|
||||
|
||||
|
||||
@@ -3,12 +3,13 @@ package com.jetbrains.python.debugger;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.PyNamedParameter;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author traff
|
||||
*/
|
||||
public class PyCallSignatureTypeProvider extends PyTypeProviderBase {
|
||||
public PyType getParameterType(final PyNamedParameter param, final PyFunction func, TypeEvalContext context) {
|
||||
public PyType getParameterType(@NotNull final PyNamedParameter param, @NotNull final PyFunction func, @NotNull TypeEvalContext context) {
|
||||
final String name = param.getName();
|
||||
if (name != null) {
|
||||
final String typeName = ((PySignatureCacheManagerImpl)PySignatureCacheManager.getInstance(param.getProject())).findParameterType(func, name);
|
||||
|
||||
@@ -318,8 +318,7 @@ public class PyBuiltinCache {
|
||||
synchronized (myStdlibTypeCache) {
|
||||
final Ref<PyType> ref = myStdlibTypeCache.get(key);
|
||||
if (ref != null) {
|
||||
final PyType pyType = ref.get();
|
||||
if (pyType instanceof PyClassType && !((PyClassType)pyType).isValid()) {
|
||||
if (!isValid(ref.get())) {
|
||||
myStdlibTypeCache.clear();
|
||||
return null;
|
||||
}
|
||||
@@ -328,6 +327,31 @@ public class PyBuiltinCache {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValid(@Nullable PyType type) {
|
||||
if (type instanceof PyCollectionType) {
|
||||
final PyType elementType = ((PyCollectionType)type).getElementType(TypeEvalContext.fastStubOnly(null));
|
||||
if (!isValid(elementType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (type instanceof PyClassType) {
|
||||
return ((PyClassType)type).isValid();
|
||||
}
|
||||
else if (type instanceof PyUnionType) {
|
||||
for (PyType member : ((PyUnionType)type).getMembers()) {
|
||||
if (!isValid(member)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (type instanceof PyFunctionType) {
|
||||
return ((PyFunctionType)type).getFunction().isValid();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void storeStdlibType(@NotNull String key, @Nullable PyType result) {
|
||||
synchronized (myStdlibTypeCache) {
|
||||
myStdlibTypeCache.put(key, new Ref<PyType>(result));
|
||||
|
||||
@@ -204,7 +204,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyType getGenericReturnType(TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) {
|
||||
private PyType getGenericReturnType(@NotNull TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) {
|
||||
if (typeEvalContext.maySwitchToAST(this)) {
|
||||
PyAnnotation anno = getAnnotation();
|
||||
if (anno != null) {
|
||||
|
||||
@@ -9,11 +9,12 @@ import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
|
||||
import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
|
||||
import com.jetbrains.python.psi.resolve.QualifiedNameResolverImpl;
|
||||
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
|
||||
import com.jetbrains.python.psi.types.PyClassType;
|
||||
import com.jetbrains.python.psi.types.PyClassTypeImpl;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -40,6 +41,7 @@ public class PyPsiFacadeImpl extends PyPsiFacade {
|
||||
return PyClassNameIndex.findClass(qName, myProject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PyClassType createClassType(@NotNull PyClass pyClass, boolean isDefinition) {
|
||||
return new PyClassTypeImpl(pyClass, isDefinition);
|
||||
@@ -47,7 +49,25 @@ public class PyPsiFacadeImpl extends PyPsiFacade {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String findShortestImportableName(PsiElement importer, VirtualFile targetFile) {
|
||||
return QualifiedNameFinder.findShortestImportableName(importer, targetFile);
|
||||
public PyType createUnionType(@NotNull Collection<PyType> members) {
|
||||
return PyUnionType.union(members);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PyType createTupleType(@NotNull Collection<PyType> members, @NotNull PsiElement anchor) {
|
||||
return PyTupleType.create(anchor, members.toArray(new PyType[members.size()]));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PyType parseTypeAnnotation(@NotNull String annotation, @NotNull PsiElement anchor) {
|
||||
return PyTypeParser.getTypeByName(anchor, annotation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String findShortestImportableName(@NotNull VirtualFile targetFile, @NotNull PsiElement anchor) {
|
||||
return QualifiedNameFinder.findShortestImportableName(anchor, targetFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class QualifiedNameFinder {
|
||||
* the name with fewest qualifiers is selected.
|
||||
*/
|
||||
@Nullable
|
||||
public static String findShortestImportableName(PsiElement foothold, @NotNull VirtualFile vfile) {
|
||||
public static String findShortestImportableName(@NotNull PsiElement foothold, @NotNull VirtualFile vfile) {
|
||||
final PyQualifiedName qName = findShortestImportableQName(foothold, vfile);
|
||||
return qName == null ? null : qName.toString();
|
||||
}
|
||||
|
||||
@@ -53,6 +53,15 @@ public class PyABCUtil {
|
||||
if (PyNames.MAPPING.equals(superClassName)) {
|
||||
return isSized && hasIter && isContainer && hasGetItem && hasMethod(subClass, PyNames.KEYS, inherited);
|
||||
}
|
||||
if (PyNames.COMPLEX.equals(superClassName)) {
|
||||
return hasMethod(subClass, "__complex__", inherited);
|
||||
}
|
||||
if (PyNames.REAL.equals(superClassName)) {
|
||||
return hasMethod(subClass, "__float__", inherited);
|
||||
}
|
||||
if (PyNames.INTEGRAL.equals(superClassName)) {
|
||||
return hasMethod(subClass, "__int__", inherited);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,9 +50,6 @@ public class PyTypeChecker {
|
||||
if (actual instanceof PyTypeReference) {
|
||||
return match(expected, ((PyTypeReference)actual).resolve(null, context), context, substitutions, false);
|
||||
}
|
||||
if (isUnknown(actual)) {
|
||||
return true;
|
||||
}
|
||||
if (expected instanceof PyGenericType && substitutions != null) {
|
||||
final PyGenericType generic = (PyGenericType)expected;
|
||||
final PyType subst = substitutions.get(generic);
|
||||
@@ -72,6 +69,9 @@ public class PyTypeChecker {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (isUnknown(actual)) {
|
||||
return true;
|
||||
}
|
||||
if (actual instanceof PyUnionType) {
|
||||
for (PyType m : ((PyUnionType)actual).getMembers()) {
|
||||
if (!match(expected, m, context, substitutions, recursive)) {
|
||||
@@ -149,7 +149,7 @@ public class PyTypeChecker {
|
||||
}
|
||||
|
||||
public static boolean isUnknown(@Nullable PyType type) {
|
||||
if (type == null || type instanceof PyTypeReference) {
|
||||
if (type == null || type instanceof PyTypeReference || type instanceof PyGenericType) {
|
||||
return true;
|
||||
}
|
||||
if (type instanceof PyUnionType) {
|
||||
@@ -165,29 +165,34 @@ public class PyTypeChecker {
|
||||
|
||||
public static boolean hasGenerics(@Nullable PyType type, @NotNull TypeEvalContext context) {
|
||||
final Set<PyGenericType> collected = new HashSet<PyGenericType>();
|
||||
collectGenerics(type, context, collected);
|
||||
collectGenerics(type, context, collected, new HashSet<PyType>());
|
||||
return !collected.isEmpty();
|
||||
}
|
||||
|
||||
private static void collectGenerics(@Nullable PyType type, @NotNull TypeEvalContext context, @NotNull Set<PyGenericType> collected) {
|
||||
private static void collectGenerics(@Nullable PyType type, @NotNull TypeEvalContext context, @NotNull Set<PyGenericType> collected,
|
||||
@NotNull Set<PyType> visited) {
|
||||
if (visited.contains(type)) {
|
||||
return;
|
||||
}
|
||||
visited.add(type);
|
||||
if (type instanceof PyGenericType) {
|
||||
collected.add((PyGenericType)type);
|
||||
}
|
||||
else if (type instanceof PyUnionType) {
|
||||
final PyUnionType union = (PyUnionType)type;
|
||||
for (PyType t : union.getMembers()) {
|
||||
collectGenerics(t, context, collected);
|
||||
collectGenerics(t, context, collected, visited);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyCollectionType) {
|
||||
final PyCollectionType collection = (PyCollectionType)type;
|
||||
collectGenerics(collection.getElementType(context), context, collected);
|
||||
collectGenerics(collection.getElementType(context), context, collected, visited);
|
||||
}
|
||||
else if (type instanceof PyTupleType) {
|
||||
final PyTupleType tuple = (PyTupleType)type;
|
||||
final int n = tuple.getElementCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
collectGenerics(tuple.getElementType(i), context, collected);
|
||||
collectGenerics(tuple.getElementType(i), context, collected, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +257,7 @@ public class PyTypeChecker {
|
||||
// Collect generic params of object type
|
||||
final Set<PyGenericType> generics = new LinkedHashSet<PyGenericType>();
|
||||
final PyType qualifierType = receiver != null ? receiver.getType(context) : null;
|
||||
collectGenerics(qualifierType, context, generics);
|
||||
collectGenerics(qualifierType, context, generics, new HashSet<PyType>());
|
||||
for (PyGenericType t : generics) {
|
||||
substitutions.put(t, t);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
class B(object):
|
||||
def __init__(self, x):
|
||||
"""
|
||||
:type x: T
|
||||
:rtype: B of T
|
||||
"""
|
||||
self._x = x
|
||||
|
||||
def foo(self):
|
||||
"""
|
||||
:rtype: T
|
||||
"""
|
||||
return self._x
|
||||
|
||||
class C(B):
|
||||
def bar(self):
|
||||
expr = self.foo()
|
||||
return 'foo' + expr #pass
|
||||
@@ -0,0 +1,18 @@
|
||||
class B(object):
|
||||
def __init__(self, x):
|
||||
"""
|
||||
:type x: T
|
||||
:rtype: B of T
|
||||
"""
|
||||
self._x = x
|
||||
|
||||
def foo(self):
|
||||
"""
|
||||
:rtype: T
|
||||
"""
|
||||
return self._x
|
||||
|
||||
class C(B):
|
||||
def bar(self):
|
||||
expr = self.foo()
|
||||
return expr.upper() #pass
|
||||
@@ -140,4 +140,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase {
|
||||
public void testAssignedOperator() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7244
|
||||
public void testGenericArguments() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -175,6 +175,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-7244
|
||||
public void testAttributesOfGenerics() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py");
|
||||
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
|
||||
|
||||
Reference in New Issue
Block a user