mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-14774 Hide annotations for *args/**kwargs parameters in "Change signature" dialog
It was done already for normal (not starred) parameters of function. Validation of names (parts after leading '*') for such parameters is performed now as well. I've also added a few more warnings in "Change signature" dialog, namely: * Multiple parameters with single or double star * Several starred parameters have the same name
This commit is contained in:
@@ -628,6 +628,7 @@ refactoring.change.signature.dialog.validation.name.defined=Name is already defi
|
||||
refactoring.change.signature.dialog.validation.function.name=Incorrect function name
|
||||
refactoring.change.signature.dialog.validation.parameter.name=Incorrect parameter name
|
||||
refactoring.change.signature.dialog.validation.multiple.star=Multiple * arguments are not allowed
|
||||
refactoring.change.signature.dialog.validation.multiple.double.star=Multiple ** arguments are not allowed
|
||||
refactoring.change.signature.dialog.validation.default.missing=Default value is missing
|
||||
refactoring.change.signature.dialog.validation.parameter.missing=Parameter name is missing
|
||||
refactoring.change.signature.dialog.default.value.checkbox=Use default value in signature:
|
||||
|
||||
+14
-4
@@ -140,10 +140,11 @@ public class PyChangeSignatureDialog extends ChangeSignatureDialogBase<PyParamet
|
||||
PyParameterTableModelItem info = parameters.get(index);
|
||||
final PyParameterInfo parameter = info.parameter;
|
||||
final String name = parameter.getName();
|
||||
if (parameterNames.contains(name)) {
|
||||
final String nameWithoutStars = StringUtil.trimLeading(name, '*').trim();
|
||||
if (parameterNames.contains(nameWithoutStars)) {
|
||||
return PyBundle.message("ANN.duplicate.param.name");
|
||||
}
|
||||
parameterNames.add(name);
|
||||
parameterNames.add(nameWithoutStars);
|
||||
|
||||
if (name.equals("*")) {
|
||||
hadSingleStar = true;
|
||||
@@ -155,16 +156,25 @@ public class PyChangeSignatureDialog extends ChangeSignatureDialogBase<PyParamet
|
||||
if (hadKeywordContainer) {
|
||||
return PyBundle.message("ANN.starred.param.after.kwparam");
|
||||
}
|
||||
if (hadSingleStar) {
|
||||
if (hadSingleStar || hadPositionalContainer) {
|
||||
return PyBundle.message("refactoring.change.signature.dialog.validation.multiple.star");
|
||||
}
|
||||
if (!isNameValid(name.substring(1), myProject)) {
|
||||
return PyBundle.message("refactoring.change.signature.dialog.validation.parameter.name");
|
||||
}
|
||||
hadPositionalContainer = true;
|
||||
}
|
||||
else if (name.startsWith("**")) {
|
||||
hadKeywordContainer = true;
|
||||
if (hadSingleStar && !hadParamsAfterSingleStar) {
|
||||
return PyBundle.message("ANN.named.arguments.after.star");
|
||||
}
|
||||
if (hadKeywordContainer) {
|
||||
return PyBundle.message("refactoring.change.signature.dialog.validation.multiple.double.star");
|
||||
}
|
||||
if (!isNameValid(name.substring(2), myProject)) {
|
||||
return PyBundle.message("refactoring.change.signature.dialog.validation.parameter.name");
|
||||
}
|
||||
hadKeywordContainer = true;
|
||||
}
|
||||
else {
|
||||
if (!isNameValid(name, myProject)) {
|
||||
|
||||
+14
-15
@@ -310,7 +310,7 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
|
||||
final PyParameter[] oldParameters = function.getParameterList().getParameters();
|
||||
for (PyParameterInfo paramInfo: changeInfo.getNewParameters()) {
|
||||
if (paramInfo.getOldIndex() >= 0 && paramInfo.isRenamed()) {
|
||||
final String newName = StringUtil.trimLeading(paramInfo.getName(), '*');
|
||||
final String newName = StringUtil.trimLeading(paramInfo.getName(), '*').trim();
|
||||
final UsageInfo[] usages = RenameUtil.findUsages(oldParameters[paramInfo.getOldIndex()], newName, true, false, null);
|
||||
for (UsageInfo info : usages) {
|
||||
RenameUtil.rename(info, newName);
|
||||
@@ -355,11 +355,12 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
|
||||
final PsiElement parameterList = baseMethod.getParameterList();
|
||||
|
||||
final PyParameterInfo[] parameters = changeInfo.getNewParameters();
|
||||
StringBuilder builder = new StringBuilder("def foo(");
|
||||
final StringBuilder builder = new StringBuilder("def foo(");
|
||||
final PyStringLiteralExpression docstring = baseMethod.getDocStringExpression();
|
||||
final PyParameter[] oldParameters = baseMethod.getParameterList().getParameters();
|
||||
final PyElementGenerator generator = PyElementGenerator.getInstance(baseMethod.getProject());
|
||||
for (int i = 0; i != parameters.length; ++i) {
|
||||
PyParameterInfo info = parameters[i];
|
||||
final PyParameterInfo info = parameters[i];
|
||||
|
||||
final int oldIndex = info.getOldIndex();
|
||||
if (i != 0 && oldIndex < oldParameters.length) {
|
||||
@@ -367,15 +368,14 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
|
||||
}
|
||||
|
||||
if (docstring != null && oldIndex < 0) {
|
||||
final String replacement =
|
||||
new PyDocstringGenerator(baseMethod).withParam("param", info.getName()).docStringAsText();
|
||||
PyExpression str =
|
||||
PyElementGenerator.getInstance(baseMethod.getProject()).createDocstring(replacement).getExpression();
|
||||
docstring.replace(str);
|
||||
final String replacement = new PyDocstringGenerator(baseMethod).withParam("param", info.getName()).docStringAsText();
|
||||
final PyExpression newDocstring = generator.createDocstring(replacement).getExpression();
|
||||
docstring.replace(newDocstring);
|
||||
}
|
||||
|
||||
if (oldIndex < oldParameters.length)
|
||||
if (oldIndex < oldParameters.length) {
|
||||
builder.append(info.getName());
|
||||
}
|
||||
if (oldIndex >= 0 && oldIndex < oldParameters.length) {
|
||||
final PyParameter parameter = oldParameters[oldIndex];
|
||||
if (parameter instanceof PyNamedParameter) {
|
||||
@@ -386,18 +386,17 @@ public class PyChangeSignatureUsageProcessor implements ChangeSignatureUsageProc
|
||||
}
|
||||
}
|
||||
final String defaultValue = info.getDefaultValue();
|
||||
if (defaultValue != null && info.getDefaultInSignature() && !StringUtil.isEmpty(defaultValue)) {
|
||||
if (defaultValue != null && info.getDefaultInSignature() && StringUtil.isNotEmpty(defaultValue)) {
|
||||
builder.append(" = ").append(defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
builder.append("): pass");
|
||||
|
||||
final PyParameterList parameterList1 =
|
||||
PyElementGenerator.getInstance(baseMethod.getProject())
|
||||
.createFromText(LanguageLevel.forElement(baseMethod), PyFunction.class,
|
||||
builder.toString()).getParameterList();
|
||||
parameterList.replace(parameterList1);
|
||||
final PyParameterList newParameterList = generator.createFromText(LanguageLevel.forElement(baseMethod),
|
||||
PyFunction.class,
|
||||
builder.toString()).getParameterList();
|
||||
parameterList.replace(newParameterList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
-3
@@ -48,9 +48,22 @@ public class PyMethodDescriptor implements MethodDescriptor<PyParameterInfo, Str
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PyParameter parameter = parameters[i];
|
||||
final PyExpression defaultValue = parameter.getDefaultValue();
|
||||
final String name = parameter instanceof PyNamedParameter && !((PyNamedParameter)parameter).isPositionalContainer() &&
|
||||
!((PyNamedParameter)parameter).isKeywordContainer() ? parameter.getName() : parameter.getText();
|
||||
parameterInfos.add(new PyParameterInfo(i, name, defaultValue == null? null : defaultValue.getText(),
|
||||
final String name;
|
||||
if (parameter instanceof PyNamedParameter) {
|
||||
if (((PyNamedParameter)parameter).isPositionalContainer()) {
|
||||
name = "*" + parameter.getName();
|
||||
}
|
||||
else if (((PyNamedParameter)parameter).isKeywordContainer()) {
|
||||
name = "**" + parameter.getName();
|
||||
}
|
||||
else {
|
||||
name = parameter.getName();
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = parameter.getText();
|
||||
}
|
||||
parameterInfos.add(new PyParameterInfo(i, name, defaultValue == null ? null : defaultValue.getText(),
|
||||
defaultValue != null && !StringUtil.isEmptyOrSpaces(defaultValue.getText())));
|
||||
}
|
||||
return parameterInfos;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
def func(*foo, **bar):
|
||||
pass
|
||||
@@ -0,0 +1,2 @@
|
||||
def func(foo, **bar):
|
||||
pass
|
||||
@@ -0,0 +1,2 @@
|
||||
def func(foo, *bar):
|
||||
pass
|
||||
@@ -0,0 +1,2 @@
|
||||
def func(**kwargs):
|
||||
pass
|
||||
+50
@@ -19,7 +19,10 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
@@ -198,6 +201,53 @@ public class PyChangeSignatureTest extends PyTestCase {
|
||||
PyBundle.message("ANN.non.default.param.after.default"));
|
||||
}
|
||||
|
||||
// PY-14774
|
||||
public void testAnnotationsForStarredParametersAreNotShownInDialog() throws Exception {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() {
|
||||
public void run() {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, "def func(a, b:int, *args: tuple, c:list, d:str='foo', ** kwargs:dict):\n" +
|
||||
" pass");
|
||||
final PyFunction function = (PyFunction)new PyChangeSignatureHandler().findTargetMember(myFixture.getFile(), myFixture.getEditor());
|
||||
assertNotNull(function);
|
||||
final List<String> expected = Arrays.asList("a", "b", "*args", "c", "d", "**kwargs");
|
||||
final List<PyParameterInfo> parameters = new PyMethodDescriptor(function).getParameters();
|
||||
assertEquals(expected, ContainerUtil.map(parameters, new Function<PyParameterInfo, String>() {
|
||||
@Override
|
||||
public String fun(PyParameterInfo info) {
|
||||
return info.getOldName();
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testDuplicateNamesOfStarredParameters() throws Exception {
|
||||
final PyParameterInfo firstParam = new PyParameterInfo(0, "*foo", null, false);
|
||||
firstParam.setName("*bar");
|
||||
doValidationTest(null, Arrays.asList(firstParam, new PyParameterInfo(1, "**bar", null, false)),
|
||||
PyBundle.message("ANN.duplicate.param.name"));
|
||||
}
|
||||
|
||||
public void testMultipleSingleStarredParameters() throws Exception {
|
||||
final PyParameterInfo firstParam = new PyParameterInfo(0, "foo", null, false);
|
||||
firstParam.setName("*foo");
|
||||
doValidationTest(null, Arrays.asList(firstParam, new PyParameterInfo(1, "*bar", null, false)),
|
||||
PyBundle.message("refactoring.change.signature.dialog.validation.multiple.star"));
|
||||
}
|
||||
|
||||
public void testMultipleDoubleStarredParameters() throws Exception {
|
||||
final PyParameterInfo firstParam = new PyParameterInfo(0, "foo", null, false);
|
||||
firstParam.setName("**foo");
|
||||
doValidationTest(null, Arrays.asList(firstParam, new PyParameterInfo(1, "**bar", null, false)),
|
||||
PyBundle.message("refactoring.change.signature.dialog.validation.multiple.double.star"));
|
||||
}
|
||||
|
||||
public void testParameterNameWithMoreThanTwoStars() throws Exception {
|
||||
final PyParameterInfo firstParam = new PyParameterInfo(0, "**kwargs", null, false);
|
||||
firstParam.setName("***kwargs");
|
||||
doValidationTest(null, Arrays.asList(firstParam), PyBundle.message("refactoring.change.signature.dialog.validation.parameter.name"));
|
||||
}
|
||||
|
||||
public void doChangeSignatureTest(@Nullable String newName, @Nullable List<PyParameterInfo> parameters) {
|
||||
myFixture.configureByFile("refactoring/changeSignature/" + getTestName(true) + ".before.py");
|
||||
changeSignature(newName, parameters);
|
||||
|
||||
Reference in New Issue
Block a user