mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Collect metaclass members while calculating class member names (PY-21408)
This commit is contained in:
@@ -662,6 +662,9 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<String> getMemberNames(boolean inherited, @NotNull TypeEvalContext context) {
|
||||
// PyNamedTupleType.getMemberNames provide names that we are not able to visit,
|
||||
// so this method could not be replaced with PyClassLikeType.visitMembers
|
||||
|
||||
final Set<String> result = new LinkedHashSet<>();
|
||||
|
||||
for (PyFunction function : myClass.getMethods()) {
|
||||
@@ -692,11 +695,35 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
result.addAll(ancestorType.getMemberNames(false, context));
|
||||
}
|
||||
}
|
||||
|
||||
result.addAll(getMetaClassMemberNames(context));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<String> getMetaClassMemberNames(@NotNull TypeEvalContext context) {
|
||||
if (!myClass.isNewStyleClass(context)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
final PyClassLikeType typeType = getMetaClassType(context, true);
|
||||
if (typeType == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
if (isDefinition()) {
|
||||
return typeType.getMemberNames(true, context);
|
||||
}
|
||||
else if (typeType instanceof PyClassType) {
|
||||
final List<PyTargetExpression> typeInstanceAttributes = ((PyClassType)typeType).getPyClass().getInstanceAttributes();
|
||||
return ContainerUtil.map2SetNotNull(typeInstanceAttributes, PyTargetExpression::getName);
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
private void addOwnClassMembers(PsiElement expressionHook,
|
||||
Set<String> namesAlready,
|
||||
boolean suppressParentheses,
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
class B1(type):
|
||||
meta_attr = "meta_attr"
|
||||
|
||||
|
||||
class A1(metaclass=B1):
|
||||
pass
|
||||
|
||||
|
||||
def print_A1(a):
|
||||
print(a.__name__)
|
||||
print(a.meta_attr)
|
||||
|
||||
|
||||
def print_unknown(a):
|
||||
print(a.unknown)
|
||||
|
||||
|
||||
print_A1(A1)
|
||||
print_unknown(<warning descr="Type 'Type[A1]' doesn't have expected attribute 'unknown'">A1</warning>)
|
||||
|
||||
|
||||
class B2(type):
|
||||
def __init__(self, what, bases, dict):
|
||||
self.meta_attr = "meta_attr"
|
||||
super().__init__(what, bases, dict)
|
||||
|
||||
|
||||
class A2(metaclass=B2):
|
||||
pass
|
||||
|
||||
|
||||
def print_A2(a):
|
||||
print(a.meta_attr)
|
||||
|
||||
|
||||
print_A2(A2())
|
||||
print_unknown(<warning descr="Type 'A2' doesn't have expected attribute 'unknown'">A2()</warning>)
|
||||
@@ -446,4 +446,9 @@ public class PyTypeCheckerInspectionTest extends PyInspectionTestCase {
|
||||
public void testMatchingOpenFunctionCallTypesPy2() {
|
||||
doMultiFileTest();
|
||||
}
|
||||
|
||||
// PY-21408
|
||||
public void testClassMetaAttrsAgainstStructural() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON30, this::doTest);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user