diff --git a/python/python-ast/src/com/jetbrains/python/ast/PyAstNamedParameter.java b/python/python-ast/src/com/jetbrains/python/ast/PyAstNamedParameter.java index 25ed95f725fe..5f30e25a7938 100644 --- a/python/python-ast/src/com/jetbrains/python/ast/PyAstNamedParameter.java +++ b/python/python-ast/src/com/jetbrains/python/ast/PyAstNamedParameter.java @@ -17,9 +17,7 @@ package com.jetbrains.python.ast; import com.intellij.lang.ASTNode; import com.intellij.psi.*; -import com.intellij.psi.stubs.IStubElementType; -import com.intellij.psi.stubs.StubElement; -import com.jetbrains.python.PyElementTypes; +import com.intellij.util.ObjectUtils; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.ast.impl.ParamHelperCore; @@ -94,7 +92,17 @@ public interface PyAstNamedParameter extends PyAstParameter, PsiNamedElement, Ps * Includes asterisks for *param and **param, and name. */ @NotNull - String getRepr(boolean includeDefaultValue); + default String getRepr(boolean includeDefaultValue) { + final StringBuilder sb = new StringBuilder(); + + sb.append(ParamHelperCore.getNameInSignature(this)); + + if (includeDefaultValue) { + sb.append(ObjectUtils.notNull(ParamHelperCore.getDefaultValuePartInSignature(getDefaultValueText(), false), "")); + } + + return sb.toString(); + } @Override @NotNull diff --git a/python/python-ast/src/com/jetbrains/python/ast/impl/ParamHelperCore.java b/python/python-ast/src/com/jetbrains/python/ast/impl/ParamHelperCore.java index 8440740928db..0bcf6adf8224 100644 --- a/python/python-ast/src/com/jetbrains/python/ast/impl/ParamHelperCore.java +++ b/python/python-ast/src/com/jetbrains/python/ast/impl/ParamHelperCore.java @@ -1,10 +1,14 @@ package com.jetbrains.python.ast.impl; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.ast.PyAstExpression; +import com.jetbrains.python.ast.PyAstNamedParameter; import com.jetbrains.python.ast.PyAstStringLiteralExpression; import com.jetbrains.python.psi.PyStringLiteralCoreUtil; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @ApiStatus.Experimental @@ -12,6 +16,49 @@ public final class ParamHelperCore { private ParamHelperCore() { } + @NotNull + public static String getNameInSignature(@NotNull PyAstNamedParameter parameter) { + final StringBuilder sb = new StringBuilder(); + + if (parameter.isPositionalContainer()) sb.append("*"); + else if (parameter.isKeywordContainer()) sb.append("**"); + + final String name = parameter.getName(); + sb.append(name != null ? name : "..."); + + return sb.toString(); + } + + /** + * @param defaultValue string returned by {@link PyCallableParameter#getDefaultValueText()} or {@link PyParameter#getDefaultValueText()}. + * @param parameterRenderedAsTyped true if parameter is rendered with type annotation. + * @return equal sign (surrounded with spaces if {@code parameterRenderedAsTyped}) + + * {@code defaultValue} (with body escaped if it is a string literal) + */ + @Nullable + @Contract("null, _->null") + public static String getDefaultValuePartInSignature(@Nullable String defaultValue, boolean parameterRenderedAsTyped) { + if (defaultValue == null) return null; + + final StringBuilder sb = new StringBuilder(); + + // According to PEP 8 equal sign should be surrounded by spaces if annotation is present + sb.append(parameterRenderedAsTyped ? " = " : "="); + + final Pair quotes = PyStringLiteralCoreUtil.getQuotes(defaultValue); + if (quotes != null) { + 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(defaultValue); + } + + return sb.toString(); + } + /** * @param defaultValue expression returned by {@link PyCallableParameter#getDefaultValue()} or {@link PyParameter#getDefaultValue()}. * @return {@code defaultValue} value surrounded by quotes if it is a multi-line string literal, {@code defaultValue} text otherwise. diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java index 56d1e8843c30..e05150976303 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyNamedParameter.java @@ -38,17 +38,6 @@ public interface PyNamedParameter extends PyAstNamedParameter, PyParameter, PsiN return (PyExpression)PyAstNamedParameter.super.getDefaultValue(); } - /** - * @param includeDefaultValue if true, include the default value after an "=". - * @return canonical representation of parameter. - * Includes asterisks for *param and **param, and name. - */ - @Override - @NotNull - default String getRepr(boolean includeDefaultValue) { - return getRepr(includeDefaultValue, null); - } - /** * @param includeDefaultValue if true, include the default value after an "=". * @param context context to be used to resolve argument type diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java index ac43b62f6a06..5e702715af86 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java @@ -15,10 +15,9 @@ */ package com.jetbrains.python.psi.impl; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.python.ast.impl.ParamHelperCore; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.types.PyCallableParameter; import com.jetbrains.python.psi.types.PyCallableParameterImpl; @@ -148,15 +147,7 @@ public final class ParamHelper { @NotNull public static String getNameInSignature(@NotNull PyNamedParameter parameter) { - final StringBuilder sb = new StringBuilder(); - - if (parameter.isPositionalContainer()) sb.append("*"); - else if (parameter.isKeywordContainer()) sb.append("**"); - - final String name = parameter.getName(); - sb.append(name != null ? name : "..."); - - return sb.toString(); + return ParamHelperCore.getNameInSignature(parameter); } /** @@ -168,25 +159,7 @@ public final class ParamHelper { @Nullable @Contract("null, _->null") public static String getDefaultValuePartInSignature(@Nullable String defaultValue, boolean parameterRenderedAsTyped) { - if (defaultValue == null) return null; - - final StringBuilder sb = new StringBuilder(); - - // According to PEP 8 equal sign should be surrounded by spaces if annotation is present - sb.append(parameterRenderedAsTyped ? " = " : "="); - - final Pair quotes = PyStringLiteralCoreUtil.getQuotes(defaultValue); - if (quotes != null) { - 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(defaultValue); - } - - return sb.toString(); + return ParamHelperCore.getDefaultValuePartInSignature(defaultValue, parameterRenderedAsTyped); } public static boolean couldHaveDefaultValue(@NotNull String parameterName) {