diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyFile.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyFile.java index ce7ce1f19c9f..beb6ca91a6e0 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyFile.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyFile.java @@ -45,6 +45,12 @@ public interface PyFile extends PyElement, PsiFile, PyDocStringOwner, ScopeOwner @Nullable PyTargetExpression findTopLevelAttribute(@NotNull String name); + @NotNull + List getTypeAliasStatements(); + + @Nullable + PyTypeAliasStatement findTypeAliasStatement(@NotNull String name); + LanguageLevel getLanguageLevel(); /** diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeAliasStatement.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeAliasStatement.java index 6f497c18f720..4df7282c9d1f 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeAliasStatement.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeAliasStatement.java @@ -2,13 +2,24 @@ package com.jetbrains.python.psi; import com.intellij.psi.PsiNameIdentifierOwner; +import com.intellij.psi.StubBasedPsiElement; +import com.jetbrains.python.psi.stubs.PyTypeAliasStatementStub; import org.jetbrains.annotations.Nullable; /** * Represents Type Alias Statement added in PEP 695 */ -public interface PyTypeAliasStatement extends PyStatement, PsiNameIdentifierOwner, PyTypeParameterListOwner, PyTypedElement { +public interface PyTypeAliasStatement extends PyStatement, PsiNameIdentifierOwner, PyTypeParameterListOwner, PyTypedElement, + StubBasedPsiElement { @Nullable PyExpression getTypeExpression(); + + /** + * Returns right-hand side of the type alias statement as text. + *

+ * The text is taken from stub if the stub is presented. + */ + @Nullable + String getTypeExpressionText(); } diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameter.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameter.java index 4904bc30688e..01e13d2cfe4a 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameter.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameter.java @@ -1,19 +1,25 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.jetbrains.python.psi; -import com.intellij.lang.ASTNode; import com.intellij.psi.PsiNameIdentifierOwner; +import com.intellij.psi.StubBasedPsiElement; +import com.jetbrains.python.psi.stubs.PyTypeParameterStub; import org.jetbrains.annotations.Nullable; /** * Represents a Type Parameter that can be a part of {@link PyTypeParameterList}
* For more information see PEP 695 */ -public interface PyTypeParameter extends PyElement, PsiNameIdentifierOwner, PyTypedElement { +public interface PyTypeParameter extends PyElement, PsiNameIdentifierOwner, PyTypedElement, StubBasedPsiElement { @Nullable PyExpression getBoundExpression(); + /** + * Returns the text of the bound expression of the type parameter + *

+ * The text is taken from stub if the stub is presented. + */ @Nullable - ASTNode getNameNode(); + String getBoundExpressionText(); } diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameterList.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameterList.java index 518e8259debf..c1521463c204 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameterList.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyTypeParameterList.java @@ -1,6 +1,8 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.jetbrains.python.psi; +import com.intellij.psi.StubBasedPsiElement; +import com.jetbrains.python.psi.stubs.PyTypeParameterListStub; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -11,7 +13,7 @@ import java.util.List; * where {@code [T, U]} is the list of generic Type Parameters.
* For more information see PEP 695 */ -public interface PyTypeParameterList extends PyElement { +public interface PyTypeParameterList extends PyElement, StubBasedPsiElement { @NotNull List getTypeParameters(); diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeAliasStatementStub.java b/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeAliasStatementStub.java new file mode 100644 index 000000000000..e96d15a32135 --- /dev/null +++ b/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeAliasStatementStub.java @@ -0,0 +1,12 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.psi.stubs; + +import com.intellij.psi.stubs.NamedStub; +import com.jetbrains.python.psi.PyTypeAliasStatement; +import org.jetbrains.annotations.Nullable; + +public interface PyTypeAliasStatementStub extends NamedStub { + + @Nullable + String getTypeExpressionText(); +} diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeParameterListStub.java b/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeParameterListStub.java new file mode 100644 index 000000000000..1c7d4cdbf83c --- /dev/null +++ b/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeParameterListStub.java @@ -0,0 +1,8 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.psi.stubs; + +import com.intellij.psi.stubs.StubElement; +import com.jetbrains.python.psi.PyTypeParameterList; + +public interface PyTypeParameterListStub extends StubElement { +} diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeParameterStub.java b/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeParameterStub.java new file mode 100644 index 000000000000..d88b27bdd9cc --- /dev/null +++ b/python/python-psi-api/src/com/jetbrains/python/psi/stubs/PyTypeParameterStub.java @@ -0,0 +1,12 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.psi.stubs; + +import com.intellij.psi.stubs.NamedStub; +import com.jetbrains.python.psi.PyTypeParameter; +import org.jetbrains.annotations.Nullable; + +public interface PyTypeParameterStub extends NamedStub { + + @Nullable + String getBoundExpressionText(); +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/PyElementTypes.java b/python/python-psi-impl/src/com/jetbrains/python/PyElementTypes.java index 264628f308f3..06788837419d 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/PyElementTypes.java +++ b/python/python-psi-impl/src/com/jetbrains/python/PyElementTypes.java @@ -46,6 +46,9 @@ public interface PyElementTypes { PyStubElementType IMPORT_STATEMENT = PyStubElementTypes.IMPORT_STATEMENT; PyStubElementType TARGET_EXPRESSION = PyStubElementTypes.TARGET_EXPRESSION; + PyStubElementType TYPE_PARAMETER = PyStubElementTypes.TYPE_PARAMETER; + PyStubElementType TYPE_PARAMETER_LIST = PyStubElementTypes.TYPE_PARAMETER_LIST; + PyStubElementType TYPE_ALIAS_STATEMENT = PyStubElementTypes.TYPE_ALIAS_STATEMENT; TokenSet PARAMETER_LIST_SET = TokenSet.create(PARAMETER_LIST); @@ -55,8 +58,6 @@ public interface PyElementTypes { PyElementType PRINT_TARGET = new PyElementType("PRINT_TARGET", node -> new PyPrintTargetImpl(node)); PyElementType DECORATOR = new PyElementType("DECORATOR", node -> new PyDecoratorImpl(node)); - PyElementType TYPE_PARAMETER = new PyElementType("TYPE_PARAMETER", node -> new PyTypeParameterImpl(node)); - PyElementType TYPE_PARAMETER_LIST = new PyElementType("TYPE_PARAMETER_LIST", node -> new PyTypeParameterListImpl(node)); // Statements PyElementType EXPRESSION_STATEMENT = new PyElementType("EXPRESSION_STATEMENT", node -> new PyExpressionStatementImpl(node)); @@ -173,5 +174,4 @@ public interface PyElementTypes { PyElementType KEYWORD_PATTERN = new PyElementType("KEYWORD_PATTERN", node -> new PyKeywordPatternImpl(node)); PyElementType OR_PATTERN = new PyElementType("OR_PATTERN", node -> new PyOrPatternImpl(node)); PyElementType AS_PATTERN = new PyElementType("AS_PATTERN", node -> new PyAsPatternImpl(node)); - PyElementType TYPE_ALIAS_STATEMENT = new PyElementType("TYPE_ALIAS_STATEMENT", node -> new PyTypeAliasStatementImpl(node)); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/PyStubElementTypes.java b/python/python-psi-impl/src/com/jetbrains/python/PyStubElementTypes.java index 2e575c675426..82f2e7e6e4f0 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/PyStubElementTypes.java +++ b/python/python-psi-impl/src/com/jetbrains/python/PyStubElementTypes.java @@ -30,4 +30,7 @@ public interface PyStubElementTypes { PyStubElementType IMPORT_STATEMENT = new PyImportStatementElementType(); PyStubElementType TARGET_EXPRESSION = new PyTargetExpressionElementType(); + PyStubElementType TYPE_PARAMETER = new PyTypeParameterElementType(); + PyStubElementType TYPE_PARAMETER_LIST = new PyTypeParameterListElementType(); + PyStubElementType TYPE_ALIAS_STATEMENT = new PyTypeAliasStatementElementType(); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 9dd23d0da752..f702f4f89476 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -146,7 +146,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla @Override @Nullable public PyTypeParameterList getTypeParameterList() { - return childToPsi(PyElementTypes.TYPE_PARAMETER_LIST); + return getStubOrPsiChild(PyElementTypes.TYPE_PARAMETER_LIST); } @Override diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFileImpl.java index 60223244d64d..dece2e67c36f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -225,6 +225,17 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { return findByName(name, getTopLevelAttributes()); } + @Override + public @NotNull List getTypeAliasStatements() { + return PyPsiUtils.collectStubChildren(this, getGreenStub(), PyTypeAliasStatement.class); + } + + @Override + @Nullable + public PyTypeAliasStatement findTypeAliasStatement(@NotNull String name) { + return findByName(name, getTypeAliasStatements()); + } + @Nullable private static T findByName(@NotNull String name, @NotNull List namedElements) { for (T namedElement : namedElements) { diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 08a88f4d7a4a..c5e3cf3521e1 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -67,7 +67,7 @@ public class PyFunctionImpl extends PyBaseElementImpl implements @Override @Nullable public PyTypeParameterList getTypeParameterList() { - return childToPsi(PyElementTypes.TYPE_PARAMETER_LIST); + return getStubOrPsiChild(PyElementTypes.TYPE_PARAMETER_LIST); } private class CachedStructuredDocStringProvider implements CachedValueProvider { diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeAliasStatementImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeAliasStatementImpl.java index 1e7d3e0407dc..b5900d58416d 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeAliasStatementImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeAliasStatementImpl.java @@ -3,20 +3,31 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.stubs.IStubElementType; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.stubs.PyTypeAliasStatementStub; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyTypeAliasStatementImpl extends PyElementImpl implements PyTypeAliasStatement { +public class PyTypeAliasStatementImpl extends PyBaseElementImpl implements PyTypeAliasStatement { public PyTypeAliasStatementImpl(ASTNode astNode) { super(astNode); } + public PyTypeAliasStatementImpl(PyTypeAliasStatementStub stub) { + this(stub, PyElementTypes.TYPE_ALIAS_STATEMENT); + } + + public PyTypeAliasStatementImpl(PyTypeAliasStatementStub stub, IStubElementType nodeType) { + super(stub, nodeType); + } + + @Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) { pyVisitor.visitPyTypeAliasStatement(this); @@ -33,10 +44,24 @@ public class PyTypeAliasStatementImpl extends PyElementImpl implements PyTypeAli return (PyExpression)child; } + @Override + @Nullable + public String getTypeExpressionText() { + PyTypeAliasStatementStub stub = getStub(); + + if (stub != null) { + return stub.getTypeExpressionText(); + } + else { + PyExpression typeExpression = getTypeExpression(); + return typeExpression != null ? typeExpression.getText() : null; + } + } + @Override @Nullable public PyTypeParameterList getTypeParameterList() { - return childToPsi(PyElementTypes.TYPE_PARAMETER_LIST); + return getStubOrPsiChild(PyElementTypes.TYPE_PARAMETER_LIST); } @Override @@ -48,8 +73,15 @@ public class PyTypeAliasStatementImpl extends PyElementImpl implements PyTypeAli @Override public String getName() { - PsiElement identifier = getNameIdentifier(); - return identifier != null ? identifier.getText() : null; + PyTypeAliasStatementStub stub = getStub(); + + if (stub != null) { + return stub.getName(); + } + else { + PsiElement identifier = getNameIdentifier(); + return identifier != null ? identifier.getText() : null; + } } @Override diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterImpl.java index 9296946911e0..69e877ccfb9f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterImpl.java @@ -2,24 +2,35 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; +import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.psi.PyElementVisitor; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyTypeParameter; import com.jetbrains.python.psi.PyUtil; +import com.jetbrains.python.psi.stubs.PyTypeParameterStub; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyTypeParameterImpl extends PyElementImpl implements PyTypeParameter { +public class PyTypeParameterImpl extends PyBaseElementImpl implements PyTypeParameter { public PyTypeParameterImpl(ASTNode astNode) { super(astNode); } + public PyTypeParameterImpl(PyTypeParameterStub stub) { + this(stub, PyElementTypes.TYPE_PARAMETER); + } + + public PyTypeParameterImpl(PyTypeParameterStub stub, IStubElementType nodeType) { + super(stub, nodeType); + } + @Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) { pyVisitor.visitPyTypeParameter(this); @@ -28,8 +39,15 @@ public class PyTypeParameterImpl extends PyElementImpl implements PyTypeParamete @Override @Nullable public String getName() { - ASTNode nameNode = getNameNode(); - return nameNode != null ? nameNode.getText() : null; + PyTypeParameterStub stub = getStub(); + + if (stub != null) { + return stub.getName(); + } + else { + PsiElement identifier = getNameIdentifier(); + return identifier != null ? identifier.getText() : null; + } } @Override @@ -40,23 +58,35 @@ public class PyTypeParameterImpl extends PyElementImpl implements PyTypeParamete @Override @Nullable - public ASTNode getNameNode() { - return getNode().findChildByType(PyTokenTypes.IDENTIFIER); + public String getBoundExpressionText() { + PyTypeParameterStub stub = getStub(); + if (stub != null) { + return stub.getBoundExpressionText(); + } + + PyExpression boundExpression = getBoundExpression(); + if (boundExpression != null) { + return boundExpression.getText(); + } + + return null; } @Override @Nullable public PsiElement getNameIdentifier() { - ASTNode nameNode = getNameNode(); + ASTNode nameNode = getNode().findChildByType(PyTokenTypes.IDENTIFIER); return nameNode != null ? nameNode.getPsi() : null; } @Override public PsiElement setName(@NotNull String name) throws IncorrectOperationException { - ASTNode oldNameElement = getNameNode(); - if (oldNameElement != null) { - ASTNode nameElement = PyUtil.createNewName(this, name); - getNode().replaceChild(oldNameElement, nameElement); + PsiElement identifier = getNameIdentifier(); + if (identifier != null) { + ASTNode newName = PyUtil.createNewName(this, name); + ASTNode nameNode = identifier.getNode(); + + getNode().replaceChild(nameNode, newName); } return this; } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterListImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterListImpl.java index 190412f5ff73..2787e93c117c 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterListImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTypeParameterListImpl.java @@ -1,19 +1,29 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; +import com.intellij.psi.stubs.IStubElementType; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.psi.PyElementVisitor; import com.jetbrains.python.psi.PyTypeParameter; import com.jetbrains.python.psi.PyTypeParameterList; +import com.jetbrains.python.psi.stubs.PyTypeParameterListStub; import org.jetbrains.annotations.NotNull; import java.util.List; -public class PyTypeParameterListImpl extends PyElementImpl implements PyTypeParameterList { +public class PyTypeParameterListImpl extends PyBaseElementImpl implements PyTypeParameterList { public PyTypeParameterListImpl(ASTNode astNode) { super(astNode); } + public PyTypeParameterListImpl(PyTypeParameterListStub stub) { + this(stub, PyElementTypes.PARAMETER_LIST); + } + + public PyTypeParameterListImpl(PyTypeParameterListStub stub, IStubElementType nodeType) { + super(stub, nodeType); + } + @Override protected void acceptPyVisitor(PyElementVisitor pyVisitor) { pyVisitor.visitPyTypeParameterList(this); @@ -23,6 +33,6 @@ public class PyTypeParameterListImpl extends PyElementImpl implements PyTypePara @Override @NotNull public List getTypeParameters() { - return findChildrenByType(PyElementTypes.TYPE_PARAMETER); + return List.of(getStubOrPsiChildren(PyElementTypes.TYPE_PARAMETER, new PyTypeParameter[0])); } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeAliasStatementElementType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeAliasStatementElementType.java new file mode 100644 index 000000000000..59648560db96 --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeAliasStatementElementType.java @@ -0,0 +1,62 @@ +package com.jetbrains.python.psi.impl.stubs; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubInputStream; +import com.intellij.psi.stubs.StubOutputStream; +import com.jetbrains.python.PyElementTypes; +import com.jetbrains.python.psi.PyStubElementType; +import com.jetbrains.python.psi.PyTypeAliasStatement; +import com.jetbrains.python.psi.impl.PyTypeAliasStatementImpl; +import com.jetbrains.python.psi.stubs.PyTypeAliasStatementStub; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class PyTypeAliasStatementElementType extends PyStubElementType { + + public PyTypeAliasStatementElementType() { + super("TYPE_ALIAS_STATEMENT"); + } + + @Override + @NotNull + public PsiElement createElement(@NotNull ASTNode node) { + return new PyTypeAliasStatementImpl(node); + } + + @Override + public PyTypeAliasStatement createPsi(@NotNull PyTypeAliasStatementStub stub) { + return new PyTypeAliasStatementImpl(stub); + } + + @Override + @NotNull + public PyTypeAliasStatementStub createStub(@NotNull PyTypeAliasStatement psi, StubElement parentStub) { + return new PyTypeAliasStatementStubImpl(psi.getName(), (psi.getTypeExpression() != null ? psi.getTypeExpression().getText() : null), + parentStub, getStubElementType()); + } + + @Override + public void serialize(@NotNull PyTypeAliasStatementStub stub, @NotNull StubOutputStream dataStream) throws IOException { + dataStream.writeName(stub.getName()); + dataStream.writeName(stub.getTypeExpressionText()); + } + + @Override + @NotNull + public PyTypeAliasStatementStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException { + String name = dataStream.readNameString(); + String typeExpressionText = dataStream.readNameString(); + + return new PyTypeAliasStatementStubImpl(name, typeExpressionText, parentStub, getStubElementType()); + } + + @NotNull + protected IStubElementType getStubElementType() { + return PyElementTypes.TYPE_ALIAS_STATEMENT; + } +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeAliasStatementStubImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeAliasStatementStubImpl.java new file mode 100644 index 000000000000..e69479d81bfb --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeAliasStatementStubImpl.java @@ -0,0 +1,41 @@ +package com.jetbrains.python.psi.impl.stubs; + +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.StubBase; +import com.intellij.psi.stubs.StubElement; +import com.jetbrains.python.psi.PyTypeAliasStatement; +import com.jetbrains.python.psi.stubs.PyTypeAliasStatementStub; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PyTypeAliasStatementStubImpl extends StubBase implements PyTypeAliasStatementStub { + + private final String myName; + private final String myTypeExpressionText; + + public PyTypeAliasStatementStubImpl(@Nullable String name, + @Nullable String typeExpressionText, + @Nullable StubElement parent, + @NotNull IStubElementType stubElementType) { + super(parent, stubElementType); + myName = name; + myTypeExpressionText = typeExpressionText; + } + + @Override + @Nullable + public String getName() { + return myName; + } + + @Override + @Nullable + public String getTypeExpressionText() { + return myTypeExpressionText; + } + + @Override + public String toString() { + return "PyTypeAliasStatementStub(name=" + myName + ", type expression=" + myTypeExpressionText +")"; + } +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterElementType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterElementType.java new file mode 100644 index 000000000000..00e2b7604c0b --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterElementType.java @@ -0,0 +1,63 @@ +package com.jetbrains.python.psi.impl.stubs; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubInputStream; +import com.intellij.psi.stubs.StubOutputStream; +import com.jetbrains.python.PyElementTypes; +import com.jetbrains.python.psi.PyStubElementType; +import com.jetbrains.python.psi.PyTypeParameter; +import com.jetbrains.python.psi.impl.PyTypeParameterImpl; +import com.jetbrains.python.psi.stubs.PyTypeParameterStub; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class PyTypeParameterElementType extends PyStubElementType { + + public PyTypeParameterElementType() { + super("TYPE_PARAMETER"); + } + + @Override + public PyTypeParameter createPsi(@NotNull PyTypeParameterStub stub) { + return new PyTypeParameterImpl(stub); + } + + @Override + @NotNull + public PyTypeParameterStub createStub(@NotNull PyTypeParameter psi, StubElement parentStub) { + return new PyTypeParameterStubImpl(psi.getName(), psi.getBoundExpression() != null ? psi.getBoundExpression().getText() : null, + parentStub, getStubElementType()); + } + + @Override + public void serialize(@NotNull PyTypeParameterStub stub, @NotNull StubOutputStream dataStream) throws IOException { + dataStream.writeName(stub.getName()); + dataStream.writeName(stub.getBoundExpressionText()); + } + + @Override + @NotNull + public PyTypeParameterStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException { + String name = dataStream.readNameString(); + String boundExpressionText = dataStream.readNameString(); + return new PyTypeParameterStubImpl(name, + boundExpressionText, + parentStub, getStubElementType()); + } + + @Override + @NotNull + public PsiElement createElement(@NotNull ASTNode node) { + return new PyTypeParameterImpl(node); + } + + @NotNull + protected IStubElementType getStubElementType() { + return PyElementTypes.TYPE_PARAMETER; + } +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterListElementType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterListElementType.java new file mode 100644 index 000000000000..fc1ed5e23c9c --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterListElementType.java @@ -0,0 +1,56 @@ +package com.jetbrains.python.psi.impl.stubs; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubInputStream; +import com.intellij.psi.stubs.StubOutputStream; +import com.jetbrains.python.PyElementTypes; +import com.jetbrains.python.psi.PyStubElementType; +import com.jetbrains.python.psi.PyTypeParameterList; +import com.jetbrains.python.psi.impl.PyTypeParameterListImpl; +import com.jetbrains.python.psi.stubs.PyTypeParameterListStub; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class PyTypeParameterListElementType extends PyStubElementType { + + public PyTypeParameterListElementType() { + super("TYPE_PARAMETER_LIST"); + } + + @Override + public PyTypeParameterList createPsi(@NotNull PyTypeParameterListStub stub) { + return new PyTypeParameterListImpl(stub); + } + + @Override + @NotNull + public PyTypeParameterListStub createStub(@NotNull PyTypeParameterList psi, StubElement parentStub) { + return new PyTypeParameterListStubImpl(parentStub, getStubElementType()); + } + + @Override + public void serialize(@NotNull PyTypeParameterListStub stub, @NotNull StubOutputStream dataStream) throws IOException { + + } + + @Override + @NotNull + public PyTypeParameterListStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException { + return new PyTypeParameterListStubImpl(parentStub, getStubElementType()); + } + + @Override + @NotNull + public PsiElement createElement(@NotNull ASTNode node) { + return new PyTypeParameterListImpl(node); + } + + protected IStubElementType getStubElementType() { + return PyElementTypes.TYPE_PARAMETER_LIST; + } +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterListStubImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterListStubImpl.java new file mode 100644 index 000000000000..6376eb6c6cc8 --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterListStubImpl.java @@ -0,0 +1,13 @@ +package com.jetbrains.python.psi.impl.stubs; + +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.StubBase; +import com.intellij.psi.stubs.StubElement; +import com.jetbrains.python.psi.PyTypeParameterList; +import com.jetbrains.python.psi.stubs.PyTypeParameterListStub; + +public class PyTypeParameterListStubImpl extends StubBase implements PyTypeParameterListStub { + public PyTypeParameterListStubImpl(StubElement parent, IStubElementType stubElementType) { + super(parent, stubElementType); + } +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterStubImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterStubImpl.java new file mode 100644 index 000000000000..6d7bac643490 --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/stubs/PyTypeParameterStubImpl.java @@ -0,0 +1,41 @@ +package com.jetbrains.python.psi.impl.stubs; + +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.stubs.StubBase; +import com.intellij.psi.stubs.StubElement; +import com.jetbrains.python.psi.PyTypeParameter; +import com.jetbrains.python.psi.stubs.PyTypeParameterStub; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PyTypeParameterStubImpl extends StubBase implements PyTypeParameterStub { + + private final String myName; + private final String myBoundExpressionText; + + public PyTypeParameterStubImpl(@Nullable String name, + @Nullable String boundExpressionText, + @Nullable StubElement parent, + @NotNull IStubElementType stubElementType) { + super(parent, stubElementType); + myName = name; + myBoundExpressionText = boundExpressionText; + } + + @Override + @Nullable + public String getBoundExpressionText() { + return myBoundExpressionText; + } + + @Override + @Nullable + public String getName() { + return myName; + } + + @Override + public String toString() { + return "PyTypeParameterStub(name=" + myName + ", bound=" + myBoundExpressionText + ")"; + } +} diff --git a/python/testData/stubs/TypeAliasStatement.py b/python/testData/stubs/TypeAliasStatement.py new file mode 100644 index 000000000000..f2b6f0e45882 --- /dev/null +++ b/python/testData/stubs/TypeAliasStatement.py @@ -0,0 +1 @@ +type myType[T, U: str] = Union[T, U] \ No newline at end of file diff --git a/python/testData/stubs/TypeParameterListInClassDeclaration.py b/python/testData/stubs/TypeParameterListInClassDeclaration.py new file mode 100644 index 000000000000..59e98d96ccf8 --- /dev/null +++ b/python/testData/stubs/TypeParameterListInClassDeclaration.py @@ -0,0 +1,3 @@ +class Clazz[T, U: str]: + a: T + b: U \ No newline at end of file diff --git a/python/testData/stubs/TypeParameterListInFunctionDeclaration.py b/python/testData/stubs/TypeParameterListInFunctionDeclaration.py new file mode 100644 index 000000000000..1c6a55328aaa --- /dev/null +++ b/python/testData/stubs/TypeParameterListInFunctionDeclaration.py @@ -0,0 +1,2 @@ +def foo[T, U: str](a: T, b: U): + pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java index dd9c979d85c3..c49f75bfb8d7 100644 --- a/python/testSrc/com/jetbrains/python/PyStubsTest.java +++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java @@ -1090,6 +1090,71 @@ public class PyStubsTest extends PyTestCase { assertNotParsed(file); } + // PY-62608 + public void testTypeParameterListInFunctionDeclaration() { + PyFile file = getTestFile(); + PyFunction function = file.findTopLevelFunction("foo"); + + PyTypeParameter firstTypeParameter = function.getTypeParameterList().getTypeParameters().get(0); + PyTypeParameter secondTypeParameter = function.getTypeParameterList().getTypeParameters().get(1); + + assertNotNull(firstTypeParameter); + assertNotNull(secondTypeParameter); + + assertEquals("T", firstTypeParameter.getName()); + assertEquals("U", secondTypeParameter.getName()); + + assertNull(firstTypeParameter.getBoundExpressionText()); + assertEquals(secondTypeParameter.getBoundExpressionText(), "str"); + + assertNotParsed(file); + } + + // PY-62608 + public void testTypeParameterListInClassDeclaration() { + PyFile file = getTestFile(); + PyClass cls = file.findTopLevelClass("Clazz"); + + PyTypeParameter firstTypeParameter = cls.getTypeParameterList().getTypeParameters().get(0); + PyTypeParameter secondTypeParameter = cls.getTypeParameterList().getTypeParameters().get(1); + + assertNotNull(firstTypeParameter); + assertNotNull(secondTypeParameter); + + + assertEquals("T", firstTypeParameter.getName()); + assertEquals("U", secondTypeParameter.getName()); + + + assertNull(firstTypeParameter.getBoundExpressionText()); + assertEquals(secondTypeParameter.getBoundExpressionText(), "str"); + + assertNotParsed(file); + } + + // PY-62608 + public void testTypeAliasStatement() { + PyFile file = getTestFile(); + PyTypeAliasStatement typeAliasStatement = file.findTypeAliasStatement("myType"); + + assertNotNull(typeAliasStatement); + + PyTypeParameter firstTypeParameter = typeAliasStatement.getTypeParameterList().getTypeParameters().get(0); + PyTypeParameter secondTypeParameter = typeAliasStatement.getTypeParameterList().getTypeParameters().get(1); + + + assertNotNull(firstTypeParameter); + assertNotNull(secondTypeParameter); + + assertEquals("T", firstTypeParameter.getName()); + assertEquals("U", secondTypeParameter.getName()); + + assertNull(firstTypeParameter.getBoundExpressionText()); + assertEquals(secondTypeParameter.getBoundExpressionText(), "str"); + + assertNotParsed(file); + } + private void doTestTypingTypedDictArguments() { doTestTypedDict("name", Arrays.asList("x", "y"), Arrays.asList("str", "int"), QualifiedName.fromComponents("TypedDict"));