From 6238d926c2ea47513212daa0a61041013aa40cac Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 21 Jan 2014 00:51:59 +0400 Subject: [PATCH] Store metaclass qualified name in class stub for better performance --- .../python/psi/stubs/PyClassStub.java | 4 +++- .../python/psi/PyFileElementType.java | 2 +- .../python/psi/impl/PyClassImpl.java | 23 +++++++++++++++---- .../psi/impl/stubs/PyClassElementType.java | 9 +++++++- .../psi/impl/stubs/PyClassStubImpl.java | 13 +++++++++-- .../MetaclassStub/a.py | 5 ++++ .../MetaclassStub/m1.py | 7 ++++++ ...Py3UnresolvedReferencesInspectionTest.java | 20 ++++++++++++++++ 8 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py diff --git a/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java b/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java index 02b212c725f0..2ca1e2a9c7c9 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java +++ b/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java @@ -20,13 +20,15 @@ package com.jetbrains.python.psi.stubs; import com.intellij.psi.stubs.NamedStub; -import com.jetbrains.python.psi.PyClass; import com.intellij.psi.util.QualifiedName; +import com.jetbrains.python.psi.PyClass; +import org.jetbrains.annotations.Nullable; import java.util.List; public interface PyClassStub extends NamedStub { QualifiedName[] getSuperClasses(); + @Nullable QualifiedName getMetaClass(); List getSlots(); String getDocString(); } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/psi/PyFileElementType.java b/python/src/com/jetbrains/python/psi/PyFileElementType.java index 07d87c91ccf2..150745e2dbbb 100644 --- a/python/src/com/jetbrains/python/psi/PyFileElementType.java +++ b/python/src/com/jetbrains/python/psi/PyFileElementType.java @@ -63,7 +63,7 @@ public class PyFileElementType extends IStubFileElementType { @Override public int getStubVersion() { // Don't forget to update versions of indexes that use the updated stub-based elements - return 48; + return 49; } @Nullable diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 6928810ccbfe..1346f9423348 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1170,11 +1170,24 @@ public class PyClassImpl extends PyPresentableElementImpl implement @Nullable @Override public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context) { - final PyExpression expression = getMetaClassExpression(); - if (expression != null) { - final PyType type = context.getType(expression); - if (type instanceof PyClassLikeType) { - return (PyClassLikeType)type; + if (context.maySwitchToAST(this)) { + final PyExpression expression = getMetaClassExpression(); + if (expression != null) { + final PyType type = context.getType(expression); + if (type instanceof PyClassLikeType) { + return (PyClassLikeType)type; + } + } + } + else { + final PyClassStub stub = getStub(); + final QualifiedName name = stub != null ? stub.getMetaClass() : PyQualifiedNameFactory.fromExpression(getMetaClassExpression()); + final PsiFile file = getContainingFile(); + if (file instanceof PyFile) { + final PyFile pyFile = (PyFile)file; + if (name != null) { + return classTypeFromQName(name, pyFile, context); + } } } return null; diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java index 813fb5c3c260..e29c71c092be 100644 --- a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java +++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java @@ -59,12 +59,16 @@ public class PyClassElementType extends PyStubElementType final PyExpression[] exprs = psi.getSuperClassExpressions(); List superClasses = new ArrayList(); for (PyExpression expression : exprs) { + if (expression instanceof PyKeywordArgument) { + continue; + } expression = PyClassImpl.unfoldClass(expression); superClasses.add(PyQualifiedNameFactory.fromExpression(expression)); } final PyStringLiteralExpression docStringExpression = psi.getDocStringExpression(); return new PyClassStubImpl(psi.getName(), parentStub, superClasses.toArray(new QualifiedName[superClasses.size()]), + PyQualifiedNameFactory.fromExpression(psi.getMetaClassExpression()), psi.getOwnSlots(), PyPsiUtils.strValue(docStringExpression), getStubElementType()); @@ -77,6 +81,7 @@ public class PyClassElementType extends PyStubElementType for (QualifiedName s : classes) { QualifiedName.serialize(s, dataStream); } + QualifiedName.serialize(pyClassStub.getMetaClass(), dataStream); PyFileElementType.writeNullableList(dataStream, pyClassStub.getSlots()); final String docString = pyClassStub.getDocString(); dataStream.writeUTFFast(docString != null ? docString : ""); @@ -90,9 +95,11 @@ public class PyClassElementType extends PyStubElementType for (int i = 0; i < superClassCount; i++) { superClasses[i] = QualifiedName.deserialize(dataStream); } + final QualifiedName metaClass = QualifiedName.deserialize(dataStream); List slots = PyFileElementType.readNullableList(dataStream); final String docString = dataStream.readUTFFast(); - return new PyClassStubImpl(name, parentStub, superClasses, slots, docString.length() > 0 ? docString : null, getStubElementType()); + return new PyClassStubImpl(name, parentStub, superClasses, metaClass, slots, docString.length() > 0 ? docString : null, + getStubElementType()); } public void indexStub(@NotNull final PyClassStub stub, @NotNull final IndexSink sink) { diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java index e607478ba46f..0de91810d192 100644 --- a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java @@ -21,6 +21,7 @@ import com.intellij.psi.stubs.StubElement; import com.jetbrains.python.psi.PyClass; import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.stubs.PyClassStub; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -30,14 +31,16 @@ import java.util.List; public class PyClassStubImpl extends StubBase implements PyClassStub { private final String myName; private final QualifiedName[] mySuperClasses; + @Nullable private final QualifiedName myMetaClass; private final List mySlots; private final String myDocString; - public PyClassStubImpl(final String name, StubElement parentStub, final QualifiedName[] superClasses, final List slots, - String docString, IStubElementType stubElementType) { + public PyClassStubImpl(final String name, StubElement parentStub, final QualifiedName[] superClasses, @Nullable QualifiedName metaClass, + final List slots, String docString, IStubElementType stubElementType) { super(parentStub, stubElementType); myName = name; mySuperClasses = superClasses; + myMetaClass = metaClass; mySlots = slots; myDocString = docString; } @@ -50,6 +53,12 @@ public class PyClassStubImpl extends StubBase implements PyClassStub { return mySuperClasses; } + @Nullable + @Override + public QualifiedName getMetaClass() { + return myMetaClass; + } + @Override public List getSlots() { return mySlots; diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py new file mode 100644 index 000000000000..bf0ee4488340 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py @@ -0,0 +1,5 @@ +from m1 import C + +c = C() +print(C.foo(), C.bar()) +print(c.foo()) \ No newline at end of file diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py new file mode 100644 index 000000000000..bd6222aa73fd --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py @@ -0,0 +1,7 @@ +class M(type): + def foo(cls): + pass + + +class C(metaclass=M): + pass diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java index 65cb17d2ff63..69d8455080f0 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -15,11 +15,19 @@ */ package com.jetbrains.python.inspections; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.LightProjectDescriptor; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.psi.PyClass; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.stubs.PyClassNameIndex; import org.jetbrains.annotations.NotNull; +import java.util.Collection; + /** * @author vlan */ @@ -73,6 +81,18 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + public void testMetaclassStub() { + doMultiFileTest("a.py"); + final Project project = myFixture.getProject(); + Collection classes = PyClassNameIndex.find("M", project, GlobalSearchScope.allScope(project)); + for (PyClass cls : classes) { + final PsiFile file = cls.getContainingFile(); + if (file instanceof PyFile) { + assertNotParsed((PyFile)file); + } + } + } + // PY-9011 public void testDatetimeDateAttributesOutsideClass() { doMultiFileTest("a.py");