mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-20057 Initial support of typing.Type (types of direct classes)
This commit is contained in:
@@ -62,6 +62,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
public static final String COROUTINE = "typing.Coroutine";
|
||||
public static final String NAMEDTUPLE = "typing.NamedTuple";
|
||||
public static final String GENERIC = "typing.Generic";
|
||||
public static final String TYPE = "typing.Type";
|
||||
|
||||
public static final Pattern TYPE_COMMENT_PATTERN = Pattern.compile("# *type: *(.*)");
|
||||
|
||||
@@ -482,6 +483,10 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
if (genericType != null) {
|
||||
return Ref.create(genericType);
|
||||
}
|
||||
final PyType classObjType = getClassObjectType(resolved, context);
|
||||
if (classObjType != null) {
|
||||
return Ref.create(classObjType);
|
||||
}
|
||||
final Ref<PyType> classType = getClassType(resolved, context.getTypeContext());
|
||||
if (classType != null) {
|
||||
return classType;
|
||||
@@ -501,6 +506,25 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getClassObjectType(@Nullable PsiElement resolved, @NotNull Context context) {
|
||||
if (resolved instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subsExpr = (PySubscriptionExpression)resolved;
|
||||
final PyExpression operand = subsExpr.getOperand();
|
||||
final Collection<String> operandNames = resolveToQualifiedNames(operand, context.getTypeContext());
|
||||
if (operandNames.contains(TYPE)) {
|
||||
final PyExpression indexExpr = subsExpr.getIndexExpression();
|
||||
if (indexExpr != null) {
|
||||
final PyType type = Ref.deref(getType(indexExpr, context));
|
||||
if (type instanceof PyClassType && !((PyClassType)type).isDefinition()) {
|
||||
return new PyClassTypeImpl(((PyClassType)type).getPyClass(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Ref<PyType> getAnyType(@NotNull PsiElement element) {
|
||||
final PyQualifiedNameOwner qualifiedNameOwner = as(element, PyQualifiedNameOwner.class);
|
||||
|
||||
@@ -186,6 +186,19 @@ public class PyTypeModelBuilder {
|
||||
visitor.param(this);
|
||||
}
|
||||
}
|
||||
|
||||
static class ClassObjectType extends TypeModel {
|
||||
private final TypeModel classType;
|
||||
|
||||
public ClassObjectType(TypeModel classType) {
|
||||
this.classType = classType;
|
||||
}
|
||||
|
||||
@Override
|
||||
void accept(@NotNull TypeVisitor visitor) {
|
||||
visitor.classObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds tree-like type model for PyType
|
||||
@@ -251,6 +264,9 @@ public class PyTypeModelBuilder {
|
||||
else if (type instanceof PyCallableType && !(type instanceof PyClassLikeType)) {
|
||||
result = build((PyCallableType)type);
|
||||
}
|
||||
else if (type instanceof PyClassType && !((PyClassType)type).isDefinition()) {
|
||||
result = new ClassObjectType(build(type, allowUnions));
|
||||
}
|
||||
if (result == null) {
|
||||
result = NamedType.nameOrAny(type);
|
||||
}
|
||||
@@ -309,6 +325,8 @@ public class PyTypeModelBuilder {
|
||||
void optional(OptionalType type);
|
||||
|
||||
void tuple(TupleType type);
|
||||
|
||||
void classObject(ClassObjectType type);
|
||||
}
|
||||
|
||||
private static class TypeToStringVisitor extends TypeNameVisitor {
|
||||
@@ -503,5 +521,12 @@ public class PyTypeModelBuilder {
|
||||
}
|
||||
add("]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classObject(ClassObjectType type) {
|
||||
add("Type[");
|
||||
type.classType.accept(this);
|
||||
add("]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,6 +783,42 @@ public class PyTypingTest extends PyTestCase {
|
||||
"expr = C(0).get()\n");
|
||||
}
|
||||
|
||||
// PY-20057
|
||||
public void testClassObjectType() {
|
||||
doTest("Type[MyClass]",
|
||||
"from typing import Type\n" +
|
||||
"\n" +
|
||||
"class MyClass:\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"def f(x: Type[MyClass]): \n" +
|
||||
" expr = x");
|
||||
}
|
||||
|
||||
// PY-20057
|
||||
public void testConstrainedClassObjectTypeOfParam() {
|
||||
doTest("Type[T]",
|
||||
"from typing import Type, TypeVar\n" +
|
||||
"\n" +
|
||||
"T = TypeVar('T', bound=int)\n" +
|
||||
"\n" +
|
||||
"def f(x: Type[T]):\n" +
|
||||
" expr = x");
|
||||
}
|
||||
|
||||
// PY-20057
|
||||
public void testConstrainedClassObjectTypeOfResultValue() {
|
||||
doTest("int",
|
||||
"from typing import Type, TypeVar\n" +
|
||||
"\n" +
|
||||
"T = TypeVar('T', bound=int)\n" +
|
||||
"\n" +
|
||||
"def f(x: Type[T]) -> T:\n" +
|
||||
" return x()\n" +
|
||||
"\n" +
|
||||
"expr = f(int)");
|
||||
}
|
||||
|
||||
private void doTestNoInjectedText(@NotNull String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
|
||||
|
||||
Reference in New Issue
Block a user