From b1d545291e1fed39bcd4222a97cbd3bb94384661 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Fri, 24 Jun 2016 16:10:27 +0300 Subject: [PATCH] Resolve __class__ to the corresponding PyClass PSI element --- .../python/psi/impl/PyBuiltinCache.java | 7 ++- .../psi/impl/references/PyReferenceImpl.java | 20 ++++---- .../python/psi/types/PyClassTypeImpl.java | 50 ++++++++++++------- .../com/jetbrains/python/Py3ResolveTest.java | 21 +++----- .../com/jetbrains/python/PyResolveTest.java | 18 +++---- 5 files changed, 60 insertions(+), 56 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index 7a69028df556..e408dae3ba34 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -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 diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index 921a6935b1bf..ecdaa5164f10 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -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; + } } } } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 9d9d1a2effe1..2c1c75042b59 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -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 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)) + .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) { diff --git a/python/testSrc/com/jetbrains/python/Py3ResolveTest.java b/python/testSrc/com/jetbrains/python/Py3ResolveTest.java index 26ba0baff316..4a7458f2ecad 100644 --- a/python/testSrc/com/jetbrains/python/Py3ResolveTest.java +++ b/python/testSrc/com/jetbrains/python/Py3ResolveTest.java @@ -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() { diff --git a/python/testSrc/com/jetbrains/python/PyResolveTest.java b/python/testSrc/com/jetbrains/python/PyResolveTest.java index 3b06c65f72b7..ea002c2e840b 100644 --- a/python/testSrc/com/jetbrains/python/PyResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyResolveTest.java @@ -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() {