Store parameter default value text in stub.

Avoid stub-to-ast switch while building parameter presentable text.
This commit is contained in:
Semyon Proshev
2017-08-30 20:38:14 +03:00
parent dad926bf86
commit 02c18e9429
15 changed files with 119 additions and 40 deletions
@@ -97,6 +97,7 @@ public class PyNames {
public static final String NONE = "None";
public static final String TRUE = "True";
public static final String FALSE = "False";
public static final String ELLIPSIS = "...";
public static final String TYPES_FUNCTION_TYPE = "types.FunctionType";
public static final String TYPES_METHOD_TYPE = "types.UnboundMethodType";
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -42,7 +42,8 @@ public interface PyParameter extends PyElement {
boolean hasDefaultValue();
boolean hasDefaultNoneValue();
@Nullable
String getDefaultValueText();
/**
* @return true if the parameter is the 'self' parameter of an instance attribute function or a function
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -21,10 +21,12 @@ 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>, PyAnnotationOwnerStub, PyTypeCommentOwnerStub {
boolean isPositionalContainer();
boolean isKeywordContainer();
boolean hasDefaultValue();
boolean hasDefaultNoneValue();
@Nullable
String getDefaultValueText();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -17,10 +17,13 @@ package com.jetbrains.python.psi.stubs;
import com.intellij.psi.stubs.StubElement;
import com.jetbrains.python.psi.PyTupleParameter;
import org.jetbrains.annotations.Nullable;
/**
* Tuple parameter stub, collects nested parameters from stubs.
*/
public interface PyTupleParameterStub extends StubElement<PyTupleParameter> {
boolean hasDefaultValue();
@Nullable
String getDefaultValueText();
}
@@ -50,6 +50,9 @@ public interface PyCallableParameter {
boolean hasDefaultValue();
@Nullable
String getDefaultValueText();
boolean isPositionalContainer();
boolean isKeywordContainer();
@@ -230,7 +230,8 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
return Ref.create(PyTypeUtil.toKeywordContainerType(parameter, annotationValueType));
}
if (parameter.hasDefaultNoneValue()) {
final String defaultValue = parameter.getDefaultValueText();
if (PyNames.NONE.equals(defaultValue) || PyNames.ELLIPSIS.equals(defaultValue)) {
return Ref.create(PyUnionType.union(annotationValueType, PyNoneType.INSTANCE));
}
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.psi.impl;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.types.PyCallableParameter;
@@ -121,6 +122,18 @@ public class ParamHelper {
return result.toString();
}
@Nullable
public static String getDefaultValueText(@Nullable PyExpression defaultValue) {
if (defaultValue instanceof PyStringLiteralExpression) {
final Pair<String, String> quotes = PyStringLiteralUtil.getQuotes(defaultValue.getText());
if (quotes != null) {
return quotes.getFirst() + ((PyStringLiteralExpression)defaultValue).getStringValue() + quotes.getSecond();
}
}
return defaultValue == null ? null : defaultValue.getText();
}
public interface ParamWalker {
/**
* Is called when a tuple parameter is encountered, before visiting any parameters nested in it.
@@ -174,13 +174,14 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
return getDefaultValue() != null;
}
@Nullable
@Override
public boolean hasDefaultNoneValue() {
public String getDefaultValueText() {
final PyNamedParameterStub stub = getStub();
if (stub != null) {
return stub.hasDefaultNoneValue();
return stub.getDefaultValueText();
}
return getDefaultValue() instanceof PyNoneLiteralExpression;
return ParamHelper.getDefaultValueText(getDefaultValue());
}
@NotNull
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -23,6 +23,7 @@ import com.jetbrains.python.psi.PyNamedParameter;
import com.jetbrains.python.psi.PySingleStarParameter;
import com.jetbrains.python.psi.PyTupleParameter;
import com.jetbrains.python.psi.stubs.PySingleStarParameterStub;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
@@ -56,9 +57,10 @@ public class PySingleStarParameterImpl extends PyBaseElementImpl<PySingleStarPar
return false;
}
@Nullable
@Override
public boolean hasDefaultNoneValue() {
return false;
public String getDefaultValueText() {
return null;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -22,6 +22,7 @@ import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.stubs.PyTupleParameterStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a tuple parameter as stubbed element.
@@ -36,14 +37,20 @@ public class PyTupleParameterImpl extends PyBaseElementImpl<PyTupleParameterStub
super(stub, PyElementTypes.TUPLE_PARAMETER);
}
@Override
@Nullable
public PyNamedParameter getAsNamed() {
return null; // we're not named
}
@Override
@NotNull
public PyTupleParameter getAsTuple() {
return this;
}
@Override
@Nullable
public PyExpression getDefaultValue() {
ASTNode[] nodes = getNode().getChildren(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens());
if (nodes.length > 0) {
@@ -52,6 +59,7 @@ public class PyTupleParameterImpl extends PyBaseElementImpl<PyTupleParameterStub
return null;
}
@Override
public boolean hasDefaultValue() {
final PyTupleParameterStub stub = getStub();
if (stub != null) {
@@ -61,8 +69,13 @@ public class PyTupleParameterImpl extends PyBaseElementImpl<PyTupleParameterStub
}
@Override
public boolean hasDefaultNoneValue() {
return false;
@Nullable
public String getDefaultValueText() {
final PyTupleParameterStub stub = getStub();
if (stub != null) {
return stub.getDefaultValueText();
}
return ParamHelper.getDefaultValueText(getDefaultValue());
}
@Override
@@ -70,6 +83,7 @@ public class PyTupleParameterImpl extends PyBaseElementImpl<PyTupleParameterStub
pyVisitor.visitPyTupleParameter(this);
}
@Override
@NotNull
public PyParameter[] getContents() {
return getStubOrPsiChildren(PythonDialectsTokenSetProvider.INSTANCE.getParameterTokens(), new PyParameter[0]);
@@ -81,6 +95,7 @@ public class PyTupleParameterImpl extends PyBaseElementImpl<PyTupleParameterStub
}
@Override
@NotNull
public ItemPresentation getPresentation() {
return new PyElementPresentation(this);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -40,7 +40,6 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
private static final int POSITIONAL_CONTAINER = 1;
private static final int KEYWORD_CONTAINER = 2;
private static final int HAS_DEFAULT_VALUE = 4;
private static final int HAS_DEFAULT_NONE_VALUE = 8;
public PyNamedParameterElementType() {
this("NAMED_PARAMETER");
@@ -50,22 +49,27 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
super(debugName);
}
@Override
@NotNull
public PyNamedParameter createPsi(@NotNull final PyNamedParameterStub stub) {
return new PyNamedParameterImpl(stub);
}
@Override
@NotNull
public PyNamedParameterStub createStub(@NotNull final PyNamedParameter psi, final StubElement parentStub) {
return new PyNamedParameterStubImpl(psi.getName(), psi.isPositionalContainer(), psi.isKeywordContainer(), psi.hasDefaultValue(),
psi.hasDefaultNoneValue(), psi.getTypeCommentAnnotation(), psi.getAnnotationValue() , parentStub,
psi.getDefaultValueText(), psi.getTypeCommentAnnotation(), psi.getAnnotationValue() , parentStub,
getStubElementType());
}
@Override
@NotNull
public PsiElement createElement(@NotNull final ASTNode node) {
return new PyNamedParameterImpl(node);
}
@Override
public void serialize(@NotNull final PyNamedParameterStub stub, @NotNull final StubOutputStream dataStream)
throws IOException {
dataStream.writeName(stub.getName());
@@ -74,23 +78,25 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
if (stub.isPositionalContainer()) flags |= POSITIONAL_CONTAINER;
if (stub.isKeywordContainer()) flags |= KEYWORD_CONTAINER;
if (stub.hasDefaultValue()) flags |= HAS_DEFAULT_VALUE;
if (stub.hasDefaultNoneValue()) flags |= HAS_DEFAULT_NONE_VALUE;
dataStream.writeByte(flags);
dataStream.writeName(stub.getDefaultValueText());
dataStream.writeName(stub.getTypeComment());
dataStream.writeName(stub.getAnnotation());
}
@Override
@NotNull
public PyNamedParameterStub deserialize(@NotNull final StubInputStream dataStream, final StubElement parentStub) throws IOException {
String name = StringRef.toString(dataStream.readName());
byte flags = dataStream.readByte();
final StringRef defaultValueText = dataStream.readName();
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,
(flags & HAS_DEFAULT_NONE_VALUE) != 0,
defaultValueText == null ? null : defaultValueText.getString(),
typeComment == null ? null : typeComment.getString(),
annotation == null ? null : annotation.getString(),
parentStub, getStubElementType());
@@ -108,6 +114,7 @@ public class PyNamedParameterElementType extends PyStubElementType<PyNamedParame
return super.shouldCreateStub(node);
}
@NotNull
protected IStubElementType getStubElementType() {
return PyElementTypes.NAMED_PARAMETER;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -33,13 +33,14 @@ public class PyNamedParameterStubImpl extends StubBase<PyNamedParameter> impleme
private final boolean myHasDefaultValue;
private final String myTypeCommentAnnotation;
private final String myAnnotation;
private final boolean myHasDefaultNoneValue;
@Nullable
private final String myDefaultValueText;
public PyNamedParameterStubImpl(String name,
boolean isPositionalContainer,
boolean isKeywordContainer,
boolean hasDefaultValue,
boolean hasDefaultNoneValue,
@Nullable String defaultValueText,
@Nullable String typeCommentAnnotation,
@Nullable String annotation,
StubElement parent,
@@ -51,24 +52,28 @@ public class PyNamedParameterStubImpl extends StubBase<PyNamedParameter> impleme
myHasDefaultValue = hasDefaultValue;
myTypeCommentAnnotation = typeCommentAnnotation;
myAnnotation = annotation;
myHasDefaultNoneValue = hasDefaultNoneValue;
myDefaultValueText = defaultValueText;
}
@Override
public boolean isPositionalContainer() {
return myPositionalContainer;
}
@Override
public boolean isKeywordContainer() {
return myKeywordContainer;
}
@Override
public boolean hasDefaultValue() {
return myHasDefaultValue;
}
@Nullable
@Override
public boolean hasDefaultNoneValue() {
return myHasDefaultNoneValue;
public String getDefaultValueText() {
return myDefaultValueText;
}
@Nullable
@@ -83,6 +88,7 @@ public class PyNamedParameterStubImpl extends StubBase<PyNamedParameter> impleme
return myAnnotation;
}
@Override
public String getName() {
return myName;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
import com.intellij.util.io.StringRef;
import com.jetbrains.python.psi.PyStubElementType;
import com.jetbrains.python.psi.PyTupleParameter;
import com.jetbrains.python.psi.impl.PyTupleParameterImpl;
@@ -37,27 +38,34 @@ public class PyTupleParameterElementType extends PyStubElementType<PyTupleParame
super("TUPLE_PARAMETER");
}
@Override
@NotNull
public PsiElement createElement(@NotNull final ASTNode node) {
return new PyTupleParameterImpl(node);
}
@Override
public PyTupleParameter createPsi(@NotNull PyTupleParameterStub stub) {
return new PyTupleParameterImpl(stub);
}
@Override
@NotNull
public PyTupleParameterStub createStub(@NotNull PyTupleParameter psi, StubElement parentStub) {
return new PyTupleParameterStubImpl(psi.hasDefaultValue(), parentStub);
return new PyTupleParameterStubImpl(psi.hasDefaultValue(), psi.getDefaultValueText(), parentStub);
}
@Override
@NotNull
public PyTupleParameterStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
boolean hasDefaultValue = dataStream.readBoolean();
return new PyTupleParameterStubImpl(hasDefaultValue, parentStub);
final boolean hasDefaultValue = dataStream.readBoolean();
final StringRef defaultValueText = dataStream.readName();
return new PyTupleParameterStubImpl(hasDefaultValue, defaultValueText == null ? null : defaultValueText.getString(), parentStub);
}
@Override
public void serialize(@NotNull PyTupleParameterStub stub, @NotNull StubOutputStream dataStream) throws IOException {
dataStream.writeBoolean(stub.hasDefaultValue());
dataStream.writeName(stub.getDefaultValueText());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -20,6 +20,7 @@ import com.intellij.psi.stubs.StubElement;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.PyTupleParameter;
import com.jetbrains.python.psi.stubs.PyTupleParameterStub;
import org.jetbrains.annotations.Nullable;
/**
* Implementation does nothing but marking the element type.
@@ -28,13 +29,23 @@ import com.jetbrains.python.psi.stubs.PyTupleParameterStub;
*/
public class PyTupleParameterStubImpl extends StubBase<PyTupleParameter> implements PyTupleParameterStub {
private final boolean myHasDefaultValue;
@Nullable
private final String myDefaultValueText;
protected PyTupleParameterStubImpl(boolean hasDefaultValue, StubElement parent) {
protected PyTupleParameterStubImpl(boolean hasDefaultValue, @Nullable String defaultValueText, StubElement parent) {
super(parent, PyElementTypes.TUPLE_PARAMETER);
myHasDefaultValue = hasDefaultValue;
myDefaultValueText = defaultValueText;
}
@Override
public boolean hasDefaultValue() {
return myHasDefaultValue;
}
@Nullable
@Override
public String getDefaultValueText() {
return myDefaultValueText;
}
}
@@ -112,6 +112,13 @@ public class PyCallableParameterImpl implements PyCallableParameter {
return myElement == null ? myDefaultValue != null : myElement.hasDefaultValue();
}
@Nullable
@Override
public String getDefaultValueText() {
if (myElement != null) return myElement.getDefaultValueText();
return myDefaultValue == null ? null : myDefaultValue.getText();
}
@Override
public boolean isPositionalContainer() {
final PyNamedParameter namedParameter = PyUtil.as(myElement, PyNamedParameter.class);
@@ -148,21 +155,19 @@ public class PyCallableParameterImpl implements PyCallableParameter {
sb.append(PythonDocumentationProvider.getTypeDescription(argumentType, context));
}
final PyExpression defaultValue = getDefaultValue();
final String defaultValue = getDefaultValueText();
if (defaultValueShouldBeIncluded(includeDefaultValue, defaultValue, argumentType)) {
final Pair<String, String> quotes = defaultValue instanceof PyStringLiteralExpression
? PyStringLiteralUtil.getQuotes(defaultValue.getText())
: null;
final Pair<String, String> quotes = PyStringLiteralUtil.getQuotes(defaultValue);
sb.append("=");
if (quotes != null) {
final String value = ((PyStringLiteralExpression)defaultValue).getStringValue();
final String value = defaultValue.substring(quotes.getFirst().length(), defaultValue.length() - quotes.getSecond().length());
sb.append(quotes.getFirst());
StringUtil.escapeStringCharacters(value.length(), value, sb);
sb.append(quotes.getSecond());
}
else {
sb.append(PyUtil.getReadableRepr(defaultValue, true));
sb.append(defaultValue);
}
}
@@ -208,11 +213,11 @@ public class PyCallableParameterImpl implements PyCallableParameter {
}
private static boolean defaultValueShouldBeIncluded(boolean includeDefaultValue,
@Nullable PyExpression defaultValue,
@Nullable String defaultValue,
@Nullable PyType type) {
if (!includeDefaultValue || defaultValue == null) return false;
// In case of `None` default value, it will be listed in the type as `Optional[...]` or `Union[..., None, ...]`
return type == null || !PyNames.NONE.equals(defaultValue.getText());
return type == null || !PyNames.NONE.equals(defaultValue);
}
}