From d8a1f8fd86413c7fc657bff2469a9509b495cc40 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 16 May 2017 15:09:34 +0300 Subject: [PATCH] PY-8174 Use provided arguments as default values for new parameters --- .../com/jetbrains/python/PyTokenTypes.java | 4 ++ .../quickfix/PyChangeSignatureQuickFix.java | 59 ++++++++++++------- .../python/refactoring/PyRefactoringUtil.java | 14 +++++ .../PyChangeSignatureDialog.java | 2 +- .../PyChangeSignatureProcessor.java | 8 +-- 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java b/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java index 70f636351f3a..f35ce48bee2d 100644 --- a/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java +++ b/python/psi-api/src/com/jetbrains/python/PyTokenTypes.java @@ -165,6 +165,10 @@ public class PyTokenTypes { public static final TokenSet WHITESPACE_OR_LINEBREAK = TokenSet.create(SPACE, TAB, FORMFEED, LINE_BREAK); public static final TokenSet OPEN_BRACES = TokenSet.create(LBRACKET, LBRACE, LPAR); public static final TokenSet CLOSE_BRACES = TokenSet.create(RBRACKET, RBRACE, RPAR); + + public static final TokenSet NUMERIC_LITERALS = TokenSet.create(FLOAT_LITERAL, INTEGER_LITERAL, IMAGINARY_LITERAL); + public static final TokenSet BOOL_LITERALS = TokenSet.create(TRUE_KEYWORD, FALSE_KEYWORD); + public static final TokenSet SCALAR_LITERALS = TokenSet.orSet(STRING_NODES, BOOL_LITERALS, NUMERIC_LITERALS, TokenSet.create(NONE_KEYWORD)); public static final TokenSet AUG_ASSIGN_OPERATIONS = TokenSet.create(PLUSEQ, MINUSEQ, MULTEQ, ATEQ, DIVEQ, PERCEQ, EXPEQ, GTGTEQ, LTLTEQ, ANDEQ, OREQ, XOREQ, FLOORDIVEQ); diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java index 117de83ec401..c4ffdf79bd25 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java @@ -18,6 +18,7 @@ package com.jetbrains.python.inspections.quickfix; import com.google.common.collect.Iterators; import com.google.common.collect.PeekingIterator; import com.intellij.codeInspection.LocalQuickFixOnPsiElement; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; @@ -68,7 +69,16 @@ public class PyChangeSignatureQuickFix extends LocalQuickFixOnPsiElement { final List> newParameters = new ArrayList<>(); for (PyExpression arg : mapping.getUnmappedArguments()) { if (arg instanceof PyKeywordArgument) { - newParameters.add(Pair.create(parameters.length - 1, new PyParameterInfo(-1, ((PyKeywordArgument)arg).getKeyword(), "", false))); + final String defaultValueText; + final PyExpression value = ((PyKeywordArgument)arg).getValueExpression(); + if (value != null && PyRefactoringUtil.isSimpleExpression(value) && !value.textContains('\n')) { + defaultValueText = value.getText(); + } + else { + defaultValueText = ApplicationManager.getApplication().isUnitTestMode() ? "None" : ""; + } + newParameters.add(Pair.create(parameters.length - 1, + new PyParameterInfo(-1, ((PyKeywordArgument)arg).getKeyword(), defaultValueText, true))); } else { final TypeEvalContext context = TypeEvalContext.userInitiated(function.getProject(), callExpression.getContainingFile()); @@ -77,10 +87,10 @@ public class PyChangeSignatureQuickFix extends LocalQuickFixOnPsiElement { final String paramName = PyRefactoringUtil.selectUniqueNameFromType(typeName, function.getStatementList()); newParameters.add(Pair.create(positionalParamAnchor, new PyParameterInfo(-1, paramName, "", false))); } - } + } return new PyChangeSignatureQuickFix(function, newParameters); } - + @NotNull public static PyChangeSignatureQuickFix forMismatchingMethods(@NotNull PyFunction function, @NotNull PyFunction complementary) { @@ -117,7 +127,7 @@ public class PyChangeSignatureQuickFix extends LocalQuickFixOnPsiElement { }, ", "); return "" + PyBundle.message("QFIX.change.signature.of", StringUtil.notNullize(function.getName()) + "(" + params + ")") + - ""; + ""; } @Nullable @@ -127,36 +137,45 @@ public class PyChangeSignatureQuickFix extends LocalQuickFixOnPsiElement { @Override public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) { - final PyChangeSignatureDialog dialog = new PyChangeSignatureDialog(project, createMethodDescriptor(getFunction())) { + final PyFunction function = getFunction(); + final PyMethodDescriptor descriptor = createMethodDescriptor(function); + + final PyChangeSignatureDialog dialog = new PyChangeSignatureDialog(project, descriptor) { // Similar to JavaChangeSignatureDialog.createAndPreselectNew() @Override protected int getSelectedIdx() { return (int)StreamEx.of(getParameters()).indexOf(info -> info.getOldIndex() < 0).orElse(super.getSelectedIdx()); } }; - dialog.show(); + + if (ApplicationManager.getApplication().isUnitTestMode()) { + dialog.createRefactoringProcessor().run(); + } + else { + dialog.show(); + } } @NotNull private PyMethodDescriptor createMethodDescriptor(final PyFunction function) { return new PyMethodDescriptor(function) { - @Override - public List getParameters() { - final List result = new ArrayList<>(); - final List originalParams = super.getParameters(); - final PeekingIterator> extra = Iterators.peekingIterator(myExtraParameters.iterator()); - while (extra.hasNext() && extra.peek().getFirst() < 0) { + @Override + public List getParameters() { + final List result = new ArrayList<>(); + final List originalParams = super.getParameters(); + final PeekingIterator> extra = Iterators.peekingIterator(myExtraParameters.iterator()); + while (extra.hasNext() && extra.peek().getFirst() < 0) { + result.add(extra.next().getSecond()); + } + for (int i = 0; i < originalParams.size(); i++) { + result.add(originalParams.get(i)); + while (extra.hasNext() && extra.peek().getFirst() == i) { result.add(extra.next().getSecond()); } - for (int i = 0; i < originalParams.size(); i++) { - result.add(originalParams.get(i)); - while (extra.hasNext() && extra.peek().getFirst() == i) { - result.add(extra.next().getSecond()); - } - } - return result; } - }; + return result; + } + }; } @Nullable diff --git a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java index 4448804a780c..14592a8abbe1 100644 --- a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java +++ b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java @@ -17,6 +17,7 @@ package com.jetbrains.python.refactoring; import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.find.findUsages.FindUsagesHandler; +import com.intellij.lang.ASTNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; @@ -28,6 +29,7 @@ import com.intellij.usageView.UsageInfo; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.findUsages.PyFindUsagesHandlerFactory; import com.jetbrains.python.psi.*; import com.jetbrains.python.refactoring.introduce.IntroduceValidator; @@ -397,4 +399,16 @@ public class PyRefactoringUtil { public static boolean isValidNewName(@NotNull String name, @NotNull PsiElement scopeAnchor) { return !(IntroduceValidator.isDefinedInScope(name, scopeAnchor) || PyNames.isReserved(name)); } + + public static boolean isSimpleExpression(@NotNull PyExpression value) { + if (value instanceof PyLiteralExpression) { + final ASTNode node = value.getNode(); + // Check that string literal doesn't contain multiple glued nodes + return node.getChildren(null).length == 1 && PyTokenTypes.SCALAR_LITERALS.contains(node.getFirstChildNode().getElementType()); + } + else if (value instanceof PyReferenceExpression) { + return PyUtil.isPy2ReservedWord((PyReferenceExpression)value); + } + return false; + } } diff --git a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java index aa4984030914..09ba82f0c219 100644 --- a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java +++ b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureDialog.java @@ -89,7 +89,7 @@ public class PyChangeSignatureDialog extends } @Override - protected BaseRefactoringProcessor createRefactoringProcessor() { + public BaseRefactoringProcessor createRefactoringProcessor() { final List parameters = getParameters(); return new PyChangeSignatureProcessor(myProject, myMethod.getMethod(), getMethodName(), parameters.toArray(new PyParameterInfo[parameters.size()])); diff --git a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureProcessor.java b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureProcessor.java index 7dc010b07233..9b19d26d9577 100644 --- a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureProcessor.java @@ -28,10 +28,10 @@ import org.jetbrains.annotations.NotNull; public class PyChangeSignatureProcessor extends ChangeSignatureProcessorBase { - protected PyChangeSignatureProcessor(Project project, - PyFunction method, - String newName, - PyParameterInfo[] parameterInfo) { + public PyChangeSignatureProcessor(Project project, + PyFunction method, + String newName, + PyParameterInfo[] parameterInfo) { super(project, generateChangeInfo(method, newName, parameterInfo)); }