Resolve __class__ to the corresponding PyClass PSI element

This commit is contained in:
Semyon Proshev
2016-07-07 14:18:53 +03:00
parent 938d0b960c
commit b1d545291e
5 changed files with 60 additions and 56 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 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.
@@ -371,6 +371,11 @@ public class PyBuiltinCache {
return getObjectType("staticmethod");
}
@Nullable
public PyClassType getTypeType() {
return getObjectType("type");
}
/**
* @param target an element to check.
* @return true iff target is inside the __builtins__.py
@@ -246,19 +246,17 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
LanguageLevel.forElement(myElement).isAtLeast(LanguageLevel.PYTHON30)) {
final PyFunction containingFunction = PsiTreeUtil.getParentOfType(myElement, PyFunction.class);
if (containingFunction != null && containingFunction.getContainingClass() != null) {
final PyResolveProcessor processor = new PyResolveProcessor(referencedName);
PyResolveUtil.scopeCrawlUp(processor, myElement, referencedName, containingFunction);
if (containingFunction != null) {
final PyClass containingClass = containingFunction.getContainingClass();
if (processor.getElements().isEmpty()) {
ret.addAll(
Optional
.ofNullable(PyBuiltinCache.getInstance(myElement).getObjectType())
.map(type -> type.resolveMember(PyNames.__CLASS__, myElement, AccessDirection.of(myElement), myContext))
.orElse(Collections.emptyList())
);
if (containingClass != null) {
final PyResolveProcessor processor = new PyResolveProcessor(referencedName);
PyResolveUtil.scopeCrawlUp(processor, myElement, referencedName, containingFunction);
return ret;
if (processor.getElements().isEmpty()) {
ret.add(new RatedResolveResult(RatedResolveResult.RATE_NORMAL, containingClass));
return ret;
}
}
}
}
@@ -196,24 +196,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
classMember = resolveClassMember(myClass, myIsDefinition, name, location);
if (PyNames.__CLASS__.equals(name) && !isBuiltin()) {
final LanguageLevel languageLevel = LanguageLevel.forElement(myClass);
final boolean py2K = languageLevel.isOlderThan(LanguageLevel.PYTHON30);
final boolean newStyleClass = myClass.isNewStyleClass(resolveContext.getTypeEvalContext());
final boolean py2KNewStyleClass = py2K && newStyleClass;
final boolean py2KOldStyleClass = py2K && !newStyleClass;
if (myIsDefinition && py2KOldStyleClass && classMember == null) {
return Collections.emptyList();
}
if (myIsDefinition && (py2KNewStyleClass || !py2K) || !myIsDefinition && py2KOldStyleClass) {
return Optional
.ofNullable(PyBuiltinCache.getInstance(myClass).getObjectType())
.map(type -> type.resolveMember(name, location, direction, resolveContext))
.orElse(Collections.emptyList());
}
if (PyNames.__CLASS__.equals(name)) {
return resolveDunderClass(context, classMember);
}
if (classMember != null) {
@@ -321,6 +305,36 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
return resultRef;
}
@Nullable
private List<? extends RatedResolveResult> resolveDunderClass(@NotNull TypeEvalContext context, @Nullable PsiElement classMember) {
final boolean newStyleClass = myClass.isNewStyleClass(context);
if (!myIsDefinition) {
if (newStyleClass && classMember != null) {
return ResolveResultList.to(classMember);
}
return ResolveResultList.to(
myClass.getAncestorClasses(context)
.stream()
.filter(cls -> !PyUtil.isObjectClass(cls))
.<PsiElement>map(cls -> cls.findClassAttribute(PyNames.__CLASS__, true, context))
.filter(target -> target != null)
.findFirst()
.orElse(myClass)
);
}
if (LanguageLevel.forElement(myClass).isOlderThan(LanguageLevel.PYTHON30) && !newStyleClass) {
return ResolveResultList.to(classMember);
}
return Optional
.ofNullable(PyBuiltinCache.getInstance(myClass).getTypeType())
.map(typeType -> ResolveResultList.to(typeType.getPyClass()))
.orElse(null);
}
@Nullable
@Override
public PyClassLikeType getMetaClassType(@NotNull final TypeEvalContext context, boolean inherited) {
@@ -67,8 +67,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testImplicitDunderClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "A");
}
public void testImplicitDunderDoc() {
@@ -86,8 +85,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testImplicitDunderClassWithClassAttr() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "A");
}
public void testImplicitDunderDocWithClassAttr() {
@@ -105,8 +103,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testImplicitDunderClassWithInheritedClassAttr() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "B");
}
public void testImplicitDunderDocWithInheritedClassAttr() {
@@ -124,8 +121,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testInstanceDunderClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "A");
}
public void testInstanceDunderDoc() {
@@ -216,8 +212,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testTypeDunderClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "type");
}
public void testTypeDunderDoc() {
@@ -236,8 +231,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testTypeDunderClassWithClassAttr() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "type");
}
public void testTypeDunderDocWithClassAttr() {
@@ -266,8 +260,7 @@ public class Py3ResolveTest extends PyResolveTestCase {
// PY-13734
public void testTypeDunderClassWithInheritedClassAttr() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE_3K, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "type");
}
public void testTypeDunderDocWithInheritedClassAttr() {
@@ -833,8 +833,7 @@ public class PyResolveTest extends PyResolveTestCase {
// PY-13734
public void testInstanceDunderClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "A");
}
public void testInstanceDunderDoc() {
@@ -852,8 +851,7 @@ public class PyResolveTest extends PyResolveTestCase {
// PY-13734
public void testInstanceDunderClassNewStyleClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "A");
}
public void testInstanceDunderDocNewStyleClass() {
@@ -872,8 +870,7 @@ public class PyResolveTest extends PyResolveTestCase {
// PY-13734
public void testInstanceDunderClassWithClassAttr() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "A");
}
public void testInstanceDunderDocWithClassAttr() {
@@ -992,8 +989,7 @@ public class PyResolveTest extends PyResolveTestCase {
// PY-13734
public void testTypeDunderClassNewStyleClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "type");
}
public void testTypeDunderDocNewStyleClass() {
@@ -1045,8 +1041,7 @@ public class PyResolveTest extends PyResolveTestCase {
// PY-13734
public void testTypeDunderClassWithClassAttrNewStyleClass() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "type");
}
public void testTypeDunderDocWithClassAttrNewStyleClass() {
@@ -1075,8 +1070,7 @@ public class PyResolveTest extends PyResolveTestCase {
// PY-13734
public void testTypeDunderClassWithInheritedClassAttr() {
final PyTargetExpression expression = assertResolvesTo(PyTargetExpression.class, PyNames.__CLASS__);
assertEquals(PyBuiltinCache.BUILTIN_FILE, expression.getContainingFile().getName());
assertResolvesTo(PyClass.class, "type");
}
public void testTypeDunderDocWithInheritedClassAttr() {