From 0e38f47f2177f102ba3d034f34d4c43b0524c16b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 25 Jan 2011 14:15:31 +0100 Subject: [PATCH] PyClass.iterateAncestors() split into iterateAncestors() (returning class refs, which can be not classes or unresolved classes) and iterateAncestorClasses() (returning actual resolved classes); fix PY-817 --- .../python/PythonDocumentationProvider.java | 8 +- .../python/actions/AddFieldQuickFix.java | 2 +- .../codeInsight/PyGotoSuperHandler.java | 12 +- ...ySuperAttributesCompletionContributor.java | 7 +- .../PySuperMethodCompletionContributor.java | 2 +- .../override/PyOverrideImplementUtil.java | 2 +- .../PyTypeHierarchyTreeStructure.java | 8 +- .../PyExceptionInheritInspection.java | 4 +- .../src/com/jetbrains/python/psi/PyClass.java | 4 +- .../com/jetbrains/python/psi/PyClassRef.java | 48 ++++++ .../src/com/jetbrains/python/psi/PyUtil.java | 16 +- .../python/psi/impl/PyClassImpl.java | 152 +++++++++++++----- .../python/psi/impl/PyReferenceImpl.java | 2 +- .../search/PySuperMethodsSearchExecutor.java | 2 +- .../python/psi/types/PyClassType.java | 2 +- .../structureView/PyStructureViewElement.java | 2 +- .../python/testing/PythonUnitTestUtil.java | 6 +- .../python/testing/pytest/PyTestUtil.java | 26 ++- .../PyClassicStyleClassInspection/test.py | 9 ++ 19 files changed, 217 insertions(+), 97 deletions(-) create mode 100644 python/src/com/jetbrains/python/psi/PyClassRef.java diff --git a/python/src/com/jetbrains/python/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/PythonDocumentationProvider.java index 4ac5c9dc42b3..b92cf044d63c 100644 --- a/python/src/com/jetbrains/python/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/PythonDocumentationProvider.java @@ -426,7 +426,7 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { if (cls != null && meth_name != null) { final boolean is_constructor = PyNames.INIT.equals(meth_name); // look for inherited and its doc - Iterable classes = cls.iterateAncestors(); + Iterable classes = cls.iterateAncestorClasses(); if (is_constructor) { // look at our own class again and maybe inherit class's doc classes = new ChainIterable(cls).add(classes); @@ -496,9 +496,9 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { PyClass cls = inferContainingClassOf(context); if (cls != null) { String desired_name = link.substring(LINK_TYPE_PARENT.length()); - for (PyClass parent : cls.iterateAncestors()) { - final String parent_name = parent.getName(); - if (parent_name != null && parent_name.equals(desired_name)) return parent; + for (PyClassRef parent : cls.iterateAncestors()) { + final String parent_name = parent.getClassName(); + if (parent_name != null && parent_name.equals(desired_name)) return parent.getPyClass(); } } } diff --git a/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java b/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java index e7c913c406cf..d39eacb76df9 100644 --- a/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java +++ b/python/src/com/jetbrains/python/actions/AddFieldQuickFix.java @@ -96,7 +96,7 @@ public class AddFieldQuickFix implements LocalQuickFix { return appendToInit(init, callback); } else { // no init! boldly copy ancestor's. - for (PyClass ancestor : cls.iterateAncestors()) { + for (PyClass ancestor : cls.iterateAncestorClasses()) { init = ancestor.findMethodByName(PyNames.INIT, false); if (init != null) break; } diff --git a/python/src/com/jetbrains/python/codeInsight/PyGotoSuperHandler.java b/python/src/com/jetbrains/python/codeInsight/PyGotoSuperHandler.java index 413300238542..b36b44fae95f 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyGotoSuperHandler.java +++ b/python/src/com/jetbrains/python/codeInsight/PyGotoSuperHandler.java @@ -45,13 +45,13 @@ public class PyGotoSuperHandler implements CodeInsightActionHandler { else { PyClass pyClass = PsiTreeUtil.getParentOfType(element, PyClass.class); if (pyClass != null) { - PyClass[] superClasses = PyUtil.getAllSuperClasses(pyClass); - if (superClasses.length != 0) { - if (superClasses.length == 1) { - superClasses[0].navigate(true); + List superClasses = PyUtil.getAllSuperClasses(pyClass); + if (superClasses.size() != 0) { + if (superClasses.size() == 1) { + superClasses.get(0).navigate(true); } else { - NavigationUtil.getPsiElementPopup(superClasses, CodeInsightBundle.message("goto.super.class.chooser.title")) + NavigationUtil.getPsiElementPopup(superClasses.toArray(new PyClass[superClasses.size()]), CodeInsightBundle.message("goto.super.class.chooser.title")) .showInBestPositionFor(editor); } } @@ -66,7 +66,7 @@ public class PyGotoSuperHandler implements CodeInsightActionHandler { return Collections.emptyList(); } final List result = new ArrayList(); - for (PyClass aClass: pyClass.iterateAncestors()) { + for (PyClass aClass: pyClass.iterateAncestorClasses()) { final PyFunction byName = aClass.findMethodByName(name, false); if (byName != null) { result.add(byName); diff --git a/python/src/com/jetbrains/python/codeInsight/PySuperAttributesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/PySuperAttributesCompletionContributor.java index 013b0ed332c5..7b8606722994 100644 --- a/python/src/com/jetbrains/python/codeInsight/PySuperAttributesCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/PySuperAttributesCompletionContributor.java @@ -8,7 +8,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; -import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.PyClass; +import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.PyReferenceExpression; +import com.jetbrains.python.psi.PyTargetExpression; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -42,7 +45,7 @@ public class PySuperAttributesCompletionContributor extends CompletionContributo for (PyTargetExpression expr : containingClass.getClassAttributes()) { seenNames.add(expr.getName()); } - for (PyClass ancestor : containingClass.iterateAncestors()) { + for (PyClass ancestor : containingClass.iterateAncestorClasses()) { for (PyTargetExpression expr : ancestor.getClassAttributes()) { if (!seenNames.contains(expr.getName())) { result.addElement(LookupElementBuilder.create(expr, expr.getName() + " = ")); diff --git a/python/src/com/jetbrains/python/codeInsight/PySuperMethodCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/PySuperMethodCompletionContributor.java index 7e1812eefaaa..952ee451378b 100644 --- a/python/src/com/jetbrains/python/codeInsight/PySuperMethodCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/PySuperMethodCompletionContributor.java @@ -41,7 +41,7 @@ public class PySuperMethodCompletionContributor extends CompletionContributor { for (PyFunction function : containingClass.getMethods()) { seenNames.add(function.getName()); } - for (PyClass ancestor : containingClass.iterateAncestors()) { + for (PyClass ancestor : containingClass.iterateAncestorClasses()) { for (PyFunction superMethod : ancestor.getMethods()) { if (!seenNames.contains(superMethod.getName())) { result.addElement(LookupElementBuilder.create(superMethod.getName() + superMethod.getParameterList().getText() + ":")); diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index d995c60bd3d3..5891f457188a 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -219,7 +219,7 @@ public class PyOverrideImplementUtil { @NotNull private static Collection getAllSuperFunctions(@NotNull final PyClass pyClass) { final Map superFunctions = new HashMap(); - for (PyClass aClass : pyClass.iterateAncestors()) { + for (PyClass aClass : pyClass.iterateAncestorClasses()) { for (PyFunction function : aClass.getMethods()) { if (!superFunctions.containsKey(function.getName())) { superFunctions.put(function.getName(), function); diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java index 2387a493b195..cf7cf012e595 100644 --- a/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java +++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java @@ -7,15 +7,17 @@ import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * @author Alexey.Ivanov */ public class PyTypeHierarchyTreeStructure extends PySubTypesHierarchyTreeStructure { private static PyTypeHierarchyNodeDescriptor buildHierarchyElement(@NotNull final PyClass cl) { PyTypeHierarchyNodeDescriptor descriptor = null; - PyClass[] superClasses = PyUtil.getAllSuperClasses(cl); - for (int i = superClasses.length - 1; i >= 0; --i) { - final PyClass superClass = superClasses[i]; + List superClasses = PyUtil.getAllSuperClasses(cl); + for (int i = superClasses.size() - 1; i >= 0; --i) { + final PyClass superClass = superClasses.get(i); final PyTypeHierarchyNodeDescriptor newDescriptor = new PyTypeHierarchyNodeDescriptor(descriptor, superClass, false); if (descriptor != null) { descriptor.setCachedChildren(new PyTypeHierarchyNodeDescriptor[]{newDescriptor}); diff --git a/python/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java b/python/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java index 80124608723c..df32212e0eda 100644 --- a/python/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyExceptionInheritInspection.java @@ -44,8 +44,8 @@ public class PyExceptionInheritInspection extends PyInspection { PsiElement psiElement = ((PyReferenceExpression)callee).getReference().resolve(); if (psiElement instanceof PyClass) { PyClass aClass = (PyClass) psiElement; - for (PyClass pyClass : aClass.iterateAncestors()) { - if ("Exception".equals(pyClass.getName())) { + for (PyClassRef pyClass : aClass.iterateAncestors()) { + if ("Exception".equals(pyClass.getClassName())) { return; } } diff --git a/python/src/com/jetbrains/python/psi/PyClass.java b/python/src/com/jetbrains/python/psi/PyClass.java index 2c6722d0a73b..c6b5a23689c1 100644 --- a/python/src/com/jetbrains/python/psi/PyClass.java +++ b/python/src/com/jetbrains/python/psi/PyClass.java @@ -104,7 +104,9 @@ public interface PyClass extends * A lazy way to list ancestor classes width first, in method-resolution order (MRO). * @return an iterable of ancestor classes. */ - Iterable iterateAncestors(); + Iterable iterateAncestors(); + + Iterable iterateAncestorClasses(); /** * Scan properties in order of definition, until processor returns true for one of them. diff --git a/python/src/com/jetbrains/python/psi/PyClassRef.java b/python/src/com/jetbrains/python/psi/PyClassRef.java new file mode 100644 index 000000000000..71879525185a --- /dev/null +++ b/python/src/com/jetbrains/python/psi/PyClassRef.java @@ -0,0 +1,48 @@ +package com.jetbrains.python.psi; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +/** + * @author yole + */ +public class PyClassRef { + @Nullable + private final PsiElement myElement; + + public PyClassRef(PsiElement element) { + myElement = element; + } + + @Nullable + public PyClass getPyClass() { + return myElement instanceof PyClass ? (PyClass) myElement : null; + } + + @Nullable + public String getClassName() { + return myElement instanceof PyClass ? ((PyClass) myElement).getName() : null; + } + + @Nullable + public String getQualifiedName() { + return myElement instanceof PyClass ? ((PyClass) myElement).getQualifiedName() : null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + PyClassRef that = (PyClassRef)o; + + if (myElement != null ? !myElement.equals(that.myElement) : that.myElement != null) return false; + + return true; + } + + @Override + public int hashCode() { + return myElement != null ? myElement.hashCode() : 0; + } +} diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index e83d49997d9f..93583941958d 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -342,15 +342,9 @@ public class PyUtil { * Collects superclasses of a class all the way up the inheritance chain. The order is not necessarily the MRO. */ @NotNull - public static PyClass[] getAllSuperClasses(@NotNull PyClass pyClass) { - Set superClasses = getAllSuperClassesSet(pyClass); - return superClasses.toArray(new PyClass[superClasses.size()]); - } - - @NotNull - public static Set getAllSuperClassesSet(PyClass pyClass) { - Set superClasses = new HashSet(); - for (PyClass ancestor : pyClass.iterateAncestors()) superClasses.add(ancestor); + public static List getAllSuperClasses(@NotNull PyClass pyClass) { + List superClasses = new ArrayList(); + for (PyClass ancestor : pyClass.iterateAncestorClasses()) superClasses.add(ancestor); return superClasses; } @@ -721,7 +715,7 @@ public class PyUtil { } public static boolean isExceptionClass(PyClass pyClass) { - for (PyClass c: pyClass.iterateAncestors()) { + for (PyClassRef c: pyClass.iterateAncestors()) { if ("BaseException".equals(c.getQualifiedName())) { return true; } @@ -776,7 +770,7 @@ public class PyUtil { Set flags = detectDecorationsAndWrappersOf(node); boolean isMetaclassMethod = false; PyClass type_cls = PyBuiltinCache.getInstance(node).getClass("type"); - for (PyClass ancestor_cls : cls.iterateAncestors()) { + for (PyClass ancestor_cls : cls.iterateAncestorClasses()) { if (ancestor_cls == type_cls) { isMetaclassMethod = true; break; diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 7b829afa8c8c..c32917cb8e5b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -143,13 +143,18 @@ public class PyClassImpl extends PyPresentableElementImpl implement /* The implementation is manifestly lazy wrt psi scanning and uses stack rather sparingly. It must be more efficient on deep and wide hierarchies, but it was more fun than efficiency that produced it. */ - public Iterable iterateAncestors() { + public Iterable iterateAncestors() { return new AncestorsIterable(this); } + @Override + public Iterable iterateAncestorClasses() { + return new AncestorClassesIterable(this); + } + public boolean isSubclass(PyClass parent) { if (this == parent) return true; - for (PyClass superclass : iterateAncestors()) { + for (PyClass superclass : iterateAncestorClasses()) { if (parent == superclass) return true; } return false; @@ -193,7 +198,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (slots != null) { return slots; } - for(PyClass cls: iterateAncestors()) { + for(PyClass cls: iterateAncestorClasses()) { slots = ((PyClassImpl) cls).getOwnSlots(); if (slots != null) { return slots; @@ -211,31 +216,34 @@ public class PyClassImpl extends PyPresentableElementImpl implement return PyFileImpl.getStringListFromTargetExpression(PyNames.SLOTS, getClassAttributes()); } - protected List getSuperClassesList() { + protected List getSuperClassesList() { if (PyNames.FAKE_OLD_BASE.equals(getName())) { return Collections.emptyList(); } + List result = new ArrayList(); List superClasses = resolveSuperClassesFromStub(); - if (superClasses == null) { - superClasses = new ArrayList(); + if (superClasses != null) { + for (PyClass superClass : superClasses) { + result.add(new PyClassRef(superClass)); + } + } + else { PsiElement[] superClassElements = getSuperClassElements(); for (PsiElement element : superClassElements) { - if (element instanceof PyClass) { - superClasses.add((PyClass)element); - } + result.add(new PyClassRef(element)); } } - if (superClasses.size() == 0 && !PyBuiltinCache.getInstance(this).hasInBuiltins(this)) { + if (result.size() == 0 && !PyBuiltinCache.getInstance(this).hasInBuiltins(this)) { String implicitSuperclassName = LanguageLevel.forElement(this).isPy3K() ? PyNames.OBJECT : PyNames.FAKE_OLD_BASE; PyClass implicitSuperclass = PyBuiltinCache.getInstance(this).getClass(implicitSuperclassName); if (implicitSuperclass != null) { - superClasses.add(implicitSuperclass); + result.add(new PyClassRef(implicitSuperclass)); } } - return superClasses; + return result; } @Nullable @@ -508,7 +516,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement }; Property prop = findPropertyLocally(name_filer, null, use_advanced_syntax); if (prop != null) return prop; - for (PyClass cls : iterateAncestors()) { + for (PyClass cls : iterateAncestorClasses()) { prop = ((PyClassImpl)cls).findPropertyLocally(name_filer, null, use_advanced_syntax); if (prop != null) return prop; } @@ -529,7 +537,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement Property property = findPropertyLocally(null, processor, use_advanced_syntax); if (property != null) return property; if (inherited) { - for (PyClass cls : iterateAncestors()) { + for (PyClass cls : iterateAncestorClasses()) { property = ((PyClassImpl)cls).findPropertyLocally(null, processor, use_advanced_syntax); if (property != null) return property; } @@ -624,7 +632,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (! processor.process(method)) return false; } if (inherited) { - for (PyClass ancestor : iterateAncestors()) { + for (PyClass ancestor : iterateAncestorClasses()) { if (!ancestor.visitMethods(processor, false)) { return false; } @@ -639,7 +647,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (!processor.process(nestedClass)) return false; } if (inherited) { - for (PyClass ancestor : iterateAncestors()) { + for (PyClass ancestor : iterateAncestorClasses()) { if (!((PyClassImpl) ancestor).visitNestedClasses(processor, false)) { return false; } @@ -654,7 +662,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (! processor.process(attribute)) return false; } if (inherited) { - for (PyClass ancestor : iterateAncestors()) { + for (PyClass ancestor : iterateAncestorClasses()) { if (!ancestor.visitClassAttributes(processor, false)) { return false; } @@ -767,9 +775,14 @@ public class PyClassImpl extends PyPresentableElementImpl implement PyClass objclass = PyBuiltinCache.getInstance(this).getClass("object"); if (this == objclass) return true; // a rare but possible case if (hasNewStyleMetaClass(this)) return true; - for (PyClass ancestor : iterateAncestors()) { - if (ancestor == objclass) return true; - if (hasNewStyleMetaClass(ancestor)) { + for (PyClassRef ancestor : iterateAncestors()) { + PyClass pyClass = ancestor.getPyClass(); + if (pyClass == null) { + // unknown, assume new-style class + return true; + } + if (pyClass == objclass) return true; + if (hasNewStyleMetaClass(pyClass)) { return true; } } @@ -906,32 +919,32 @@ public class PyClassImpl extends PyPresentableElementImpl implement return reference != null ? reference.get() : null; } - private static class AncestorsIterable implements Iterable { + private static class AncestorsIterable implements Iterable { private final PyClassImpl myClass; public AncestorsIterable(final PyClassImpl pyClass) { myClass = pyClass; } - public Iterator iterator() { + public Iterator iterator() { return new AncestorsIterator(myClass); } } - private static class AncestorsIterator implements Iterator { - List pending = new LinkedList(); - Set seen; - Iterator percolator; - PyClass prefetch = null; + private static class AncestorsIterator implements Iterator { + List pending = new LinkedList(); + private final Set seen; + Iterator percolator; + PyClassRef prefetch = null; private final PyClassImpl myAClass; public AncestorsIterator(PyClassImpl aClass) { myAClass = aClass; percolator = myAClass.getSuperClassesList().iterator(); - seen = new HashSet(); + seen = new HashSet(); } - private AncestorsIterator(PyClassImpl AClass, Set seen) { + private AncestorsIterator(PyClassImpl AClass, Set seen) { myAClass = AClass; this.seen = seen; percolator = myAClass.getSuperClassesList().iterator(); @@ -944,23 +957,23 @@ public class PyClassImpl extends PyPresentableElementImpl implement return prefetch != null; } - public PyClass next() { - final PyClass nextClass = getNext(); + public PyClassRef next() { + final PyClassRef nextClass = getNext(); if (nextClass == null) throw new NoSuchElementException(); return nextClass; } @Nullable - private PyClass getNext() { + private PyClassRef getNext() { iterations: while (true) { if (prefetch != null) { - PyClass ret = prefetch; + PyClassRef ret = prefetch; prefetch = null; return ret; } if (percolator.hasNext()) { - PyClassImpl it = (PyClassImpl)percolator.next(); + PyClassRef it = percolator.next(); if (seen.contains(it)) { continue iterations; // loop back is equivalent to return next(); } @@ -968,13 +981,18 @@ public class PyClassImpl extends PyPresentableElementImpl implement seen.add(it); return it; } - else if (pending.size() > 0) { - PyClassImpl it = pending.get(0); - pending.remove(0); // t, ts* = pending - percolator = new AncestorsIterator(it, new HashSet(seen)); - // loop back is equivalent to return next(); + else { + while (pending.size() > 0) { + PyClassRef it = pending.get(0); + pending.remove(0); + PyClass pyClass = it.getPyClass(); + if (pyClass != null) { + percolator = new AncestorsIterator((PyClassImpl)pyClass, new HashSet(seen)); + continue iterations; + } + } + return null; } - else return null; } } @@ -983,5 +1001,59 @@ public class PyClassImpl extends PyPresentableElementImpl implement } } + private static class AncestorClassesIterable implements Iterable { + private final PyClassImpl myClass; + + public AncestorClassesIterable(final PyClassImpl pyClass) { + myClass = pyClass; + } + + public Iterator iterator() { + return new AncestorClassesIterator(new AncestorsIterator(myClass)); + } + } + + private static class AncestorClassesIterator implements Iterator { + private final AncestorsIterator myAncestorsIterator; + private PyClass myNext; + + public AncestorClassesIterator(AncestorsIterator ancestorsIterator) { + myAncestorsIterator = ancestorsIterator; + } + + @Override + public boolean hasNext() { + if (myNext != null) { + return true; + } + while (myAncestorsIterator.hasNext()) { + PyClassRef clsRef = myAncestorsIterator.getNext(); + if (clsRef == null) { + return false; + } + myNext = clsRef.getPyClass(); + if (myNext != null) { + return true; + } + } + return false; + } + + @Override + public PyClass next() { + if (myNext == null) { + if (!hasNext()) return null; + } + PyClass next = myNext; + myNext = null; + return next; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java index 85c8abf006c9..c11583ea05f4 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java @@ -114,7 +114,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference it.set(rrr.replace(init)); } else { // init not found; maybe it's ancestor's - for (PyClass ancestor : cls.iterateAncestors()) { + for (PyClass ancestor : cls.iterateAncestorClasses()) { init = ancestor.findMethodByName(PyNames.INIT, false); if (init != null) { // add to resuls as low priority diff --git a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java index 57e6d24768b4..1d7ed969e340 100644 --- a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java +++ b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java @@ -20,7 +20,7 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor foundMethodContainingClasses = new HashSet(); if (name != null && containingClass != null) { - for (PyClass superClass : containingClass.iterateAncestors()) { + for (PyClass superClass : containingClass.iterateAncestorClasses()) { if (!queryParameters.isDeepSearch()) { boolean isAlreadyFound = false; for (PyClass alreadyFound : foundMethodContainingClasses) { diff --git a/python/src/com/jetbrains/python/psi/types/PyClassType.java b/python/src/com/jetbrains/python/psi/types/PyClassType.java index 96009e14d129..0dfdbe865422 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassType.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassType.java @@ -128,7 +128,7 @@ public class PyClassType extends UserDataHolderBase implements PyType { return new SmartList(classMember); } - for (PyClass superClass : myClass.iterateAncestors()) { + for (PyClass superClass : myClass.iterateAncestorClasses()) { PsiElement superMember = resolveClassMember(superClass, name, null); if (superMember != null) { return new SmartList(superMember); diff --git a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java index c244adc5ca2e..9e4d453ece1c 100644 --- a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java +++ b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java @@ -103,7 +103,7 @@ public class PyStructureViewElement implements StructureViewTreeElement { if (element instanceof PyClass) { PyClass the_exception = PyBuiltinCache.getInstance(element).getClass("Exception"); final PyClass cls = (PyClass)element; - for (PyClass anc : cls.iterateAncestors()) { + for (PyClass anc : cls.iterateAncestorClasses()) { if (anc == the_exception) { ((PyStructureViewElement)(children[i])).setIcon(Icons.EXCEPTION_CLASS_ICON); break; diff --git a/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java b/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java index e4b7aa7bdd05..7f06b18f9c56 100644 --- a/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java +++ b/python/src/com/jetbrains/python/testing/PythonUnitTestUtil.java @@ -8,7 +8,6 @@ import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.List; import java.util.Set; - import java.util.regex.Pattern; @@ -80,10 +79,9 @@ public class PythonUnitTestUtil { } public static boolean isTestCaseClass(@NotNull PyClass cls, Set testQualifiedNames) { - for (PyClass ancestor : cls.iterateAncestors()) { - if (ancestor == null) continue; - + for (PyClassRef ancestor : cls.iterateAncestors()) { String qName = ancestor.getQualifiedName(); + if (qName == null) continue; if (testQualifiedNames.contains(qName)) { return true; } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java index a354a5013100..95cf7233bc25 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java @@ -2,10 +2,7 @@ package com.jetbrains.python.testing.pytest; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyStatement; +import com.jetbrains.python.psi.*; import java.util.HashSet; import java.util.List; @@ -40,26 +37,21 @@ public class PyTestUtil { } public static boolean isPyTestClass(PyClass pyClass) { - for (PyClass ancestor : pyClass.iterateAncestors()) { - if (ancestor == null) continue; - + for (PyClassRef ancestor : pyClass.iterateAncestors()) { String qName = ancestor.getQualifiedName(); if (PYTHON_TEST_QUALIFIED_CLASSES.contains(qName)) { return true; } - - String name = pyClass.getName().toLowerCase(); - if (name != null && name.startsWith("test")) { - List result = Lists.newArrayList(); - for (PyFunction cls : pyClass.getMethods()) { - if (isPyTestFunction(cls)) { - result.add(cls); - } + } + + String name = pyClass.getName().toLowerCase(); + if (name != null && name.startsWith("test")) { + for (PyFunction cls : pyClass.getMethods()) { + if (isPyTestFunction(cls)) { + return true; } - if (!result.isEmpty()) return true; } } return false; } - } diff --git a/python/testData/inspections/PyClassicStyleClassInspection/test.py b/python/testData/inspections/PyClassicStyleClassInspection/test.py index f1d7f5942e23..65cdfbfce2a5 100644 --- a/python/testData/inspections/PyClassicStyleClassInspection/test.py +++ b/python/testData/inspections/PyClassicStyleClassInspection/test.py @@ -13,3 +13,12 @@ class D(C): class E: __metaclass__ = None + + +def create_meta(): + return type + +Meta = create_meta() + +class Something(Meta): + pass