PY-18816 Add dedicated fields for type annotations in suitable stubs

This commit is contained in:
Mikhail Golubev
2017-07-19 19:28:31 +03:00
parent 3f8689912e
commit b2e337f689
19 changed files with 212 additions and 71 deletions
@@ -23,4 +23,7 @@ import org.jetbrains.annotations.Nullable;
public interface PyAnnotationOwner {
@Nullable
PyAnnotation getAnnotation();
@Nullable
String getAnnotationContent();
}
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.psi.stubs;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public interface PyAnnotationOwnerStub {
/**
* @return text of the annotation element without ":" and "->"
*/
@Nullable
String getAnnotation();
}
@@ -18,9 +18,8 @@ package com.jetbrains.python.psi.stubs;
import com.intellij.psi.stubs.NamedStub;
import com.jetbrains.python.psi.PyFunction;
public interface PyFunctionStub extends NamedStub<PyFunction> {
public interface PyFunctionStub extends NamedStub<PyFunction>, PyAnnotationOwnerStub, PyTypeCommentOwnerStub {
String getDocString();
String getDeprecationMessage();
String getTypeComment();
boolean isAsync();
}
@@ -21,12 +21,9 @@ package com.jetbrains.python.psi.stubs;
import com.intellij.psi.stubs.NamedStub;
import com.jetbrains.python.psi.PyNamedParameter;
import org.jetbrains.annotations.Nullable;
public interface PyNamedParameterStub extends NamedStub<PyNamedParameter> {
public interface PyNamedParameterStub extends NamedStub<PyNamedParameter>, PyAnnotationOwnerStub, PyTypeCommentOwnerStub {
boolean isPositionalContainer();
boolean isKeywordContainer();
boolean hasDefaultValue();
@Nullable
String getTypeComment();
}
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public interface PyTargetExpressionStub extends NamedStub<PyTargetExpression> {
public interface PyTargetExpressionStub extends NamedStub<PyTargetExpression>, PyTypeCommentOwnerStub, PyAnnotationOwnerStub {
enum InitializerType {
ReferenceExpression(1),
CallExpression(2),
@@ -63,7 +63,4 @@ public interface PyTargetExpressionStub extends NamedStub<PyTargetExpression> {
@Nullable
String getDocString();
@Nullable
String getTypeComment();
}
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.psi.stubs;
import org.jetbrains.annotations.Nullable;
/**
* @author Mikhail Golubev
*/
public interface PyTypeCommentOwnerStub {
/**
* @return text of the respective type comment with "# type: " prefix stripped
*/
@Nullable
String getTypeComment();
}
@@ -44,6 +44,12 @@ public class PyTypeDeclarationStatementImpl extends PyElementImpl implements PyT
return findChildByClass(PyAnnotation.class);
}
@Nullable
@Override
public String getAnnotationContent() {
return getAnnotationContentFromPsi(this);
}
@Override
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
pyVisitor.visitPyTypeDeclarationStatement(this);
@@ -62,7 +62,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
@Override
public int getStubVersion() {
// Don't forget to update versions of indexes that use the updated stub-based elements
return 60;
return 61;
}
@Nullable
@@ -102,6 +102,12 @@ public class PyAssignmentStatementImpl extends PyElementImpl implements PyAssign
return findChildByClass(PyAnnotation.class);
}
@Nullable
@Override
public String getAnnotationContent() {
return getAnnotationContentFromPsi(this);
}
private static void addCandidate(List<PyExpression> candidates, PyExpression psi) {
if (psi instanceof PyParenthesizedExpression) {
addCandidate(candidates, ((PyParenthesizedExpression)psi).getContainedExpression());
@@ -28,8 +28,11 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.stubs.PyAnnotationOwnerStub;
import com.jetbrains.python.psi.stubs.PyTypeCommentOwnerStub;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.pyi.PyiUtil;
import org.jetbrains.annotations.NotNull;
@@ -182,7 +185,7 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
final PsiReference[] references;
if (element instanceof PyReferenceOwner) {
final PsiPolyVariantReference reference = ((PyReferenceOwner)element).getReference(resolveContext);
references = reference == null ? PsiReference.EMPTY_ARRAY : new PsiReference[] {reference};
references = reference == null ? PsiReference.EMPTY_ARRAY : new PsiReference[]{reference};
}
else {
references = element.getReferences();
@@ -196,4 +199,40 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
}
}
}
@Nullable
protected static <T extends StubBasedPsiElement<? extends PyAnnotationOwnerStub> & PyAnnotationOwner>
String getAnnotationContentFromStubOrPsi(@NotNull T elem) {
final PyAnnotationOwnerStub stub = elem.getStub();
if (stub != null) {
return stub.getAnnotation();
}
return getAnnotationContentFromPsi(elem);
}
@Nullable
protected static <T extends PyAnnotationOwner> String getAnnotationContentFromPsi(@NotNull T elem) {
final PyAnnotation annotation = elem.getAnnotation();
if (annotation != null) {
final PyExpression annotationValue = annotation.getValue();
if (annotationValue != null) {
return annotationValue.getText();
}
}
return null;
}
@Nullable
protected static <T extends StubBasedPsiElement<? extends PyTypeCommentOwnerStub> & PyTypeCommentOwner>
String getTypeCommentAnnotationFromStubOrPsi(@NotNull T elem) {
final PyTypeCommentOwnerStub stub = elem.getStub();
if (stub != null) {
return stub.getTypeComment();
}
final PsiComment comment = elem.getTypeComment();
if (comment != null) {
return PyTypingTypeProvider.getTypeCommentValue(comment.getText());
}
return null;
}
}
@@ -46,9 +46,7 @@ import com.jetbrains.python.documentation.docstrings.DocStringUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveImportUtil;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.stubs.*;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.sdk.PythonSdkType;
import icons.PythonIcons;
@@ -601,6 +599,12 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
return getStubOrPsiChild(PyElementTypes.ANNOTATION);
}
@Nullable
@Override
public String getAnnotationContent() {
return getAnnotationContentFromStubOrPsi(this);
}
@Nullable
@Override
public PsiComment getTypeComment() {
@@ -622,15 +626,7 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
@Nullable
@Override
public String getTypeCommentAnnotation() {
final PyFunctionStub stub = getStub();
if (stub != null) {
return stub.getTypeComment();
}
final PsiComment comment = getTypeComment();
if (comment != null) {
return PyTypingTypeProvider.getTypeCommentValue(comment.getText());
}
return null;
return getTypeCommentAnnotationFromStubOrPsi(this);
}
@NotNull
@@ -191,6 +191,12 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
return getStubOrPsiChild(PyElementTypes.ANNOTATION);
}
@Nullable
@Override
public String getAnnotationContent() {
return getAnnotationContentFromStubOrPsi(this);
}
@Override
@NotNull
public Icon getIcon(final int flags) {
@@ -515,14 +521,6 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
@Nullable
@Override
public String getTypeCommentAnnotation() {
final PyNamedParameterStub stub = getStub();
if (stub != null) {
return stub.getTypeComment();
}
final PsiComment comment = getTypeComment();
if (comment != null) {
return PyTypingTypeProvider.getTypeCommentValue(comment.getText());
}
return null;
return getTypeCommentAnnotationFromStubOrPsi(this);
}
}
@@ -40,11 +40,11 @@ import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
import com.jetbrains.python.documentation.docstrings.DocStringUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.references.PyQualifiedReference;
@@ -240,6 +240,12 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpression
return null;
}
@Nullable
@Override
public String getAnnotationContent() {
return getAnnotationContentFromStubOrPsi(this);
}
@Nullable
private static PyType getWithItemVariableType(TypeEvalContext context, PyWithItem item) {
final PyExpression expression = item.getExpression();
@@ -777,15 +783,6 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpression
@Nullable
@Override
public String getTypeCommentAnnotation() {
final PyTargetExpressionStub stub = getStub();
if (stub != null) {
return stub.getTypeComment();
}
final PsiComment comment = getTypeComment();
if (comment != null) {
return PyTypingTypeProvider.getTypeCommentValue(comment.getText());
}
return null;
return getTypeCommentAnnotationFromStubOrPsi(this);
}
}
@@ -56,25 +56,28 @@ public class PyFunctionElementType extends PyStubElementType<PyFunctionStub, PyF
@NotNull
public PyFunctionStub createStub(@NotNull final PyFunction psi, final StubElement parentStub) {
PyFunctionImpl function = (PyFunctionImpl)psi;
String message = function.extractDeprecationMessage();
final PyFunctionImpl function = (PyFunctionImpl)psi;
final String message = function.extractDeprecationMessage();
final PyStringLiteralExpression docStringExpression = function.getDocStringExpression();
final String typeComment = function.getTypeCommentAnnotation();
return new PyFunctionStubImpl(psi.getName(), PyPsiUtils.strValue(docStringExpression),
message,
function.isAsync(),
final String annotationContent = function.getAnnotationContent();
return new PyFunctionStubImpl(psi.getName(),
PyPsiUtils.strValue(docStringExpression),
message,
function.isAsync(),
typeComment,
annotationContent,
parentStub,
getStubElementType());
}
public void serialize(@NotNull final PyFunctionStub stub, @NotNull final StubOutputStream dataStream)
throws IOException {
public void serialize(@NotNull final PyFunctionStub stub, @NotNull final StubOutputStream dataStream) throws IOException {
dataStream.writeName(stub.getName());
dataStream.writeUTFFast(StringUtil.notNullize(stub.getDocString()));
dataStream.writeName(stub.getDeprecationMessage());
dataStream.writeBoolean(stub.isAsync());
dataStream.writeName(stub.getTypeComment());
dataStream.writeName(stub.getAnnotation());
}
@NotNull
@@ -84,10 +87,13 @@ public class PyFunctionElementType extends PyStubElementType<PyFunctionStub, PyF
StringRef deprecationMessage = dataStream.readName();
final boolean isAsync = dataStream.readBoolean();
final StringRef typeComment = dataStream.readName();
return new PyFunctionStubImpl(name, StringUtil.nullize(docString),
final StringRef annotationContent = dataStream.readName();
return new PyFunctionStubImpl(name,
StringUtil.nullize(docString),
deprecationMessage == null ? null : deprecationMessage.getString(),
isAsync,
isAsync,
typeComment == null ? null : typeComment.getString(),
annotationContent == null ? null : annotationContent.getString(),
parentStub,
getStubElementType());
}
@@ -29,15 +29,23 @@ public class PyFunctionStubImpl extends StubBase<PyFunction> implements PyFuncti
private final String myDeprecationMessage;
private final boolean myAsync;
private final String myTypeComment;
private final String myAnnotation;
public PyFunctionStubImpl(@Nullable String name, @Nullable String docString, @Nullable String deprecationMessage, boolean isAsync,
@Nullable String typeComment, final StubElement parent, @NotNull IStubElementType stubElementType) {
public PyFunctionStubImpl(@Nullable String name,
@Nullable String docString,
@Nullable String deprecationMessage,
boolean isAsync,
@Nullable String typeCommentContent,
@Nullable String annotation,
final StubElement parent,
@NotNull IStubElementType stubElementType) {
super(parent, stubElementType);
myName = name;
myDocString = docString;
myDeprecationMessage = deprecationMessage;
myAsync = isAsync;
myTypeComment = typeComment;
myTypeComment = typeCommentContent;
myAnnotation = annotation;
}
@Nullable
@@ -64,6 +72,12 @@ public class PyFunctionStubImpl extends StubBase<PyFunction> implements PyFuncti
return myTypeComment;
}
@Nullable
@Override
public String getAnnotation() {
return myAnnotation;
}
@Override
public boolean isAsync() {
return myAsync;
@@ -56,7 +56,7 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
@NotNull
public PyNamedParameterStub createStub(@NotNull final PyNamedParameter psi, final StubElement parentStub) {
return new PyNamedParameterStubImpl(psi.getName(), psi.isPositionalContainer(), psi.isKeywordContainer(), psi.hasDefaultValue(),
psi.getTypeCommentAnnotation(), parentStub, getStubElementType());
psi.getTypeCommentAnnotation(), psi.getAnnotationContent() , parentStub, getStubElementType());
}
@NotNull
@@ -74,6 +74,7 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
if (stub.hasDefaultValue()) flags |= HAS_DEFAULT_VALUE;
dataStream.writeByte(flags);
dataStream.writeName(stub.getTypeComment());
dataStream.writeName(stub.getAnnotation());
}
@NotNull
@@ -81,13 +82,14 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
String name = StringRef.toString(dataStream.readName());
byte flags = dataStream.readByte();
final StringRef typeComment = dataStream.readName();
final StringRef annotation = dataStream.readName();
return new PyNamedParameterStubImpl(name,
(flags & POSITIONAL_CONTAINER) != 0,
(flags & KEYWORD_CONTAINER) != 0,
(flags & HAS_DEFAULT_VALUE) != 0,
typeComment == null ? null : typeComment.getString(),
parentStub,
getStubElementType());
annotation == null ? null : annotation.getString(),
parentStub, getStubElementType());
}
@Override
@@ -32,12 +32,14 @@ public class PyNamedParameterStubImpl extends StubBase<PyNamedParameter> impleme
private final boolean myKeywordContainer;
private final boolean myHasDefaultValue;
private final String myTypeCommentAnnotation;
private final String myAnnotation;
public PyNamedParameterStubImpl(String name,
boolean isPositionalContainer,
boolean isKeywordContainer,
boolean hasDefaultValue,
@Nullable String typeCommentAnnotation,
@Nullable String annotation,
StubElement parent,
IStubElementType stubElementType) {
super(parent, stubElementType);
@@ -46,6 +48,7 @@ public class PyNamedParameterStubImpl extends StubBase<PyNamedParameter> impleme
myKeywordContainer = isKeywordContainer;
myHasDefaultValue = hasDefaultValue;
myTypeCommentAnnotation = typeCommentAnnotation;
myAnnotation = annotation;
}
public boolean isPositionalContainer() {
@@ -65,7 +68,13 @@ public class PyNamedParameterStubImpl extends StubBase<PyNamedParameter> impleme
public String getTypeComment() {
return myTypeCommentAnnotation;
}
@Nullable
@Override
public String getAnnotation() {
return myAnnotation;
}
public String getName() {
return myName;
}
@@ -74,10 +74,12 @@ public class PyTargetExpressionElementType extends PyStubElementType<PyTargetExp
final PyExpression assignedValue = psi.findAssignedValue();
final String docString = DocStringUtil.getDocStringValue(psi);
final String typeComment = psi.getTypeCommentAnnotation();
final String annotation = psi.getAnnotationContent();
for (CustomTargetExpressionStubType customStubType : getCustomStubTypes()) {
CustomTargetExpressionStub customStub = customStubType.createStub(psi);
if (customStub != null) {
return new PyTargetExpressionStubImpl(name, docString, typeComment, customStub, parentStub);
return new PyTargetExpressionStubImpl(name, docString, typeComment, annotation, customStub, parentStub);
}
}
PyTargetExpressionStub.InitializerType initializerType = PyTargetExpressionStub.InitializerType.Other;
@@ -93,16 +95,16 @@ public class PyTargetExpressionElementType extends PyStubElementType<PyTargetExp
initializer = ((PyReferenceExpression) callee).asQualifiedName();
}
}
return new PyTargetExpressionStubImpl(name, docString, initializerType, initializer, psi.isQualified(), typeComment, parentStub);
return new PyTargetExpressionStubImpl(name, docString, initializerType, initializer, psi.isQualified(), typeComment, annotation, parentStub);
}
public void serialize(@NotNull final PyTargetExpressionStub stub, @NotNull final StubOutputStream stream)
throws IOException {
public void serialize(@NotNull final PyTargetExpressionStub stub, @NotNull final StubOutputStream stream) throws IOException {
stream.writeName(stub.getName());
final String docString = stub.getDocString();
stream.writeUTFFast(docString != null ? docString : "");
stream.writeVarInt(stub.getInitializerType().getIndex());
stream.writeName(stub.getTypeComment());
stream.writeName(stub.getAnnotation());
final CustomTargetExpressionStub customStub = stub.getCustomStub(CustomTargetExpressionStub.class);
if (customStub != null) {
stream.writeName(customStub.getTypeClass().getCanonicalName());
@@ -115,8 +117,7 @@ public class PyTargetExpressionElementType extends PyStubElementType<PyTargetExp
}
@NotNull
public PyTargetExpressionStub deserialize(@NotNull final StubInputStream stream, final StubElement parentStub)
throws IOException {
public PyTargetExpressionStub deserialize(@NotNull final StubInputStream stream, final StubElement parentStub) throws IOException {
String name = StringRef.toString(stream.readName());
String docString = stream.readUTFFast();
if (docString.isEmpty()) {
@@ -125,19 +126,21 @@ public class PyTargetExpressionElementType extends PyStubElementType<PyTargetExp
PyTargetExpressionStub.InitializerType initializerType = PyTargetExpressionStub.InitializerType.fromIndex(stream.readVarInt());
final StringRef typeCommentRef = stream.readName();
final String typeComment = typeCommentRef == null ? null : typeCommentRef.getString();
final StringRef annotationRef = stream.readName();
final String annotation = annotationRef == null ? null : annotationRef.getString();
if (initializerType == PyTargetExpressionStub.InitializerType.Custom) {
final String typeName = stream.readName().getString();
for(CustomTargetExpressionStubType type: getCustomStubTypes()) {
if (type.getClass().getCanonicalName().equals(typeName)) {
CustomTargetExpressionStub stub = type.deserializeStub(stream);
return new PyTargetExpressionStubImpl(name, docString, typeComment, stub, parentStub);
return new PyTargetExpressionStubImpl(name, docString, typeComment, annotation, stub, parentStub);
}
}
throw new IOException("Unknown custom stub type " + typeName);
}
QualifiedName initializer = QualifiedName.deserialize(stream);
boolean isQualified = stream.readBoolean();
return new PyTargetExpressionStubImpl(name, docString, initializerType, initializer, isQualified, typeComment, parentStub);
return new PyTargetExpressionStubImpl(name, docString, initializerType, initializer, isQualified, typeComment, annotation, parentStub);
}
public boolean shouldCreateStub(final ASTNode node) {
@@ -32,18 +32,21 @@ public class PyTargetExpressionStubImpl extends StubBase<PyTargetExpression> imp
private final QualifiedName myInitializer;
private final boolean myQualified;
private final String myTypeComment;
private final String myAnnotation;
@Nullable private final String myDocString;
private final CustomTargetExpressionStub myCustomStub;
public PyTargetExpressionStubImpl(String name,
@Nullable String docString,
@Nullable String typeComment,
@Nullable String typeComment,
@Nullable String annotation,
CustomTargetExpressionStub customStub,
StubElement parent) {
super(parent, PyElementTypes.TARGET_EXPRESSION);
myName = name;
myTypeComment = typeComment;
myAnnotation = annotation;
myInitializerType = InitializerType.Custom;
myInitializer = null;
myQualified = false;
@@ -51,16 +54,18 @@ public class PyTargetExpressionStubImpl extends StubBase<PyTargetExpression> imp
myDocString = docString;
}
public PyTargetExpressionStubImpl(final String name,
public PyTargetExpressionStubImpl(final String name,
@Nullable String docString,
final InitializerType initializerType,
final QualifiedName initializer,
final boolean qualified,
@Nullable String typeComment,
String annotation,
final StubElement parentStub) {
super(parentStub, PyElementTypes.TARGET_EXPRESSION);
myName = name;
myTypeComment = typeComment;
myAnnotation = annotation;
assert initializerType != InitializerType.Custom;
myInitializerType = initializerType;
myInitializer = initializer;
@@ -107,6 +112,12 @@ public class PyTargetExpressionStubImpl extends StubBase<PyTargetExpression> imp
return myTypeComment;
}
@Nullable
@Override
public String getAnnotation() {
return myAnnotation;
}
@Override
public String toString() {
return "PyTargetExpressionStub(name=" + myName + ")";