diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java index bce13851d710..44c5108ea84e 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java @@ -180,11 +180,10 @@ public class ConvertVariadicParamIntention extends PyBaseIntentionAction { @NotNull private static List findKeywordContainerUsages(@NotNull PyFunction function, - @NotNull BiPredicate usagePredicate) { + @NotNull BiPredicate usagePredicate) { final PyParameter keywordContainer = getKeywordContainer(function.getParameterList()); - final String keywordContainerName = keywordContainer == null ? null : keywordContainer.getName(); - if (keywordContainerName != null) { + if (keywordContainer != null) { final List result = new ArrayList<>(); final Stack stack = new Stack<>(); @@ -194,7 +193,7 @@ public class ConvertVariadicParamIntention extends PyBaseIntentionAction { while (!stack.isEmpty()) { final PsiElement element = stack.pop(); - if (usagePredicate.test(element, keywordContainerName)) { + if (usagePredicate.test(element, keywordContainer)) { //noinspection unchecked result.add((T)element); } @@ -212,25 +211,31 @@ public class ConvertVariadicParamIntention extends PyBaseIntentionAction { return Collections.emptyList(); } - private static boolean isKeywordContainerSubscription(@Nullable PsiElement element, @NotNull String keywordContainerName) { - return element instanceof PySubscriptionExpression && - keywordContainerName.equals(((PySubscriptionExpression)element).getOperand().getText()); + private static boolean isKeywordContainerSubscription(@Nullable PsiElement element, @NotNull PyParameter keywordContainer) { + if (element instanceof PySubscriptionExpression) { + final PyExpression operand = ((PySubscriptionExpression)element).getOperand(); + if (operand instanceof PyReferenceExpression) { + return ((PyReferenceExpression)operand).getReference().isReferenceTo(keywordContainer); + } + } + + return false; } - private static boolean isKeywordContainerCall(@Nullable PsiElement element, @NotNull String keywordContainerName) { - return Optional - .ofNullable(PyUtil.as(element, PyCallExpression.class)) - .map(PyCallExpression::getCallee) - .map(callee -> PyUtil.as(callee, PyQualifiedExpression.class)) - .filter( - callee -> { - final PyExpression qualifier = callee.getQualifier(); - return qualifier != null && - qualifier.getText().equals(keywordContainerName) && - ArrayUtil.contains(callee.getReferencedName(), "get", "pop", PyNames.GETITEM); + private static boolean isKeywordContainerCall(@Nullable PsiElement element, @NotNull PyParameter keywordContainer) { + if (element instanceof PyCallExpression) { + final PyExpression callee = ((PyCallExpression)element).getCallee(); + if (callee instanceof PyQualifiedExpression) { + final PyQualifiedExpression qualifiedCallee = (PyQualifiedExpression)callee; + final PyExpression qualifier = qualifiedCallee.getQualifier(); + + if (qualifier instanceof PyReferenceExpression) { + return ((PyReferenceExpression)qualifier).getReference().isReferenceTo(keywordContainer) && + ArrayUtil.contains(qualifiedCallee.getReferencedName(), "get", "pop", PyNames.GETITEM); } - ) - .isPresent(); + } + } + return false; } private static void insertParameter(@NotNull PyParameterList parameterList, diff --git a/python/testData/intentions/convertVariadicParamNotOverriddenInNested.py b/python/testData/intentions/convertVariadicParamNotOverriddenInNested.py new file mode 100644 index 000000000000..c307be052226 --- /dev/null +++ b/python/testData/intentions/convertVariadicParamNotOverriddenInNested.py @@ -0,0 +1,4 @@ +def outer(**kwargs): + def nested(): + print(kwargs['foo']) + return kwargs.get('bar') \ No newline at end of file diff --git a/python/testData/intentions/convertVariadicParamNotOverriddenInNested_after.py b/python/testData/intentions/convertVariadicParamNotOverriddenInNested_after.py new file mode 100644 index 000000000000..45caaeb1b31c --- /dev/null +++ b/python/testData/intentions/convertVariadicParamNotOverriddenInNested_after.py @@ -0,0 +1,4 @@ +def outer(foo, bar=None, **kwargs): + def nested(): + print(foo) + return bar \ No newline at end of file diff --git a/python/testData/intentions/convertVariadicParamOverriddenInNested.py b/python/testData/intentions/convertVariadicParamOverriddenInNested.py new file mode 100644 index 000000000000..02edc0923db1 --- /dev/null +++ b/python/testData/intentions/convertVariadicParamOverriddenInNested.py @@ -0,0 +1,4 @@ +def outer(**kwargs): + def nested(**kwargs): + print(kwargs['foo']) + return kwargs.get('bar') \ No newline at end of file diff --git a/python/testData/intentions/convertVariadicParamOverriddenInNested_after.py b/python/testData/intentions/convertVariadicParamOverriddenInNested_after.py new file mode 100644 index 000000000000..1db13d408de7 --- /dev/null +++ b/python/testData/intentions/convertVariadicParamOverriddenInNested_after.py @@ -0,0 +1,4 @@ +def outer(bar=None, **kwargs): + def nested(**kwargs): + print(kwargs['foo']) + return bar \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java index fbf0cb504952..ad663e56a39f 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java @@ -244,6 +244,16 @@ public class PyIntentionTest extends PyTestCase { doTest(PyBundle.message("INTN.convert.variadic.param")); } + // PY-26285 + public void testConvertVariadicParamOverriddenInNested() { + doTest(PyBundle.message("INTN.convert.variadic.param")); + } + + // PY-26285 + public void testConvertVariadicParamNotOverriddenInNested() { + doTest(PyBundle.message("INTN.convert.variadic.param")); + } + public void testConvertTripleQuotedString() { //PY-2697 doTest(PyBundle.message("INTN.triple.quoted.string")); }