From aefaeaa52a4cacda546d7253b9ceb5dbb953e68b Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 7 May 2024 13:46:19 +0200 Subject: [PATCH] PY-54151 TypedDict completion at callee does not work for methods GitOrigin-RevId: 5a037490d8c24ccdd354e8396540a21294148a7e --- .../PyDictLiteralCompletionContributor.kt | 27 ++++++++---------- .../PyLiteralTypeCompletionContributor.kt | 6 ++-- .../psi/impl/PyCallExpressionHelper.java | 28 +++++++++++++++++++ .../EmptyLiteralsInMethodCall/main.py | 14 ++++++++++ .../main.py | 14 ++++++++++ .../python/PyDictLiteralCompletionTest.kt | 8 ++++++ 6 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCall/main.py create mode 100644 python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCallWithKeywordArgument/main.py diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt index e9a17d91ca2c..e347ad0a9a79 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyDictLiteralCompletionContributor.kt @@ -11,8 +11,12 @@ import com.intellij.util.ProcessingContext import com.jetbrains.python.PyNames import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil import com.jetbrains.python.psi.* -import com.jetbrains.python.psi.impl.PyPsiUtils -import com.jetbrains.python.psi.types.* +import com.jetbrains.python.psi.impl.PyCallExpressionHelper +import com.jetbrains.python.psi.resolve.PyResolveContext +import com.jetbrains.python.psi.types.PyClassType +import com.jetbrains.python.psi.types.PyType +import com.jetbrains.python.psi.types.PyTypedDictType +import com.jetbrains.python.psi.types.TypeEvalContext /** * Provides completion variants for keys of dict literals marked as TypedDict @@ -45,20 +49,11 @@ private class DictLiteralCompletionProvider : CompletionProvider getMappedParameters(@NotNull PyExpression argument, + @NotNull PyResolveContext resolveContext) { + while (argument.getParent() instanceof PyParenthesizedExpression parenthesizedExpr) { + argument = parenthesizedExpr; + } + + if (argument.getParent() instanceof PyKeywordArgument keywordArgument && keywordArgument.getValueExpression() == argument) { + argument = keywordArgument; + } + + PsiElement parent = argument.getParent(); + if (parent instanceof PyArgumentList) { + parent = parent.getParent(); + } + if (!(parent instanceof PyCallSiteExpression callSite)) { + return Collections.emptyList(); + } + + PyExpression finalArgument = argument; + return ContainerUtil.mapNotNull(mapArguments(callSite, resolveContext), mapping -> mapping.getMappedParameters().get(finalArgument)); + } + /** * Gets implicit offset from the {@code callableType}, * should be used with the methods below since they specify correct offset value. diff --git a/python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCall/main.py b/python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCall/main.py new file mode 100644 index 000000000000..cbcb4a4cfdde --- /dev/null +++ b/python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCall/main.py @@ -0,0 +1,14 @@ +from typing import TypedDict + + +class Movie (TypedDict): + name: str + age: int + + +class Foo: + def foo(self, movie: Movie) -> None: + pass + + +Foo().foo(((({})))) diff --git a/python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCallWithKeywordArgument/main.py b/python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCallWithKeywordArgument/main.py new file mode 100644 index 000000000000..977e524cb104 --- /dev/null +++ b/python/testData/completion/dictLiteralCompletion/EmptyLiteralsInMethodCallWithKeywordArgument/main.py @@ -0,0 +1,14 @@ +from typing import TypedDict + + +class Movie (TypedDict): + name: str + age: int + + +class Foo: + def foo(self, movie: Movie) -> None: + pass + + +Foo().foo(movie=((({})))) diff --git a/python/testSrc/com/jetbrains/python/PyDictLiteralCompletionTest.kt b/python/testSrc/com/jetbrains/python/PyDictLiteralCompletionTest.kt index 42ffdaf14c37..e863378feb69 100644 --- a/python/testSrc/com/jetbrains/python/PyDictLiteralCompletionTest.kt +++ b/python/testSrc/com/jetbrains/python/PyDictLiteralCompletionTest.kt @@ -9,6 +9,14 @@ class PyDictLiteralCompletionTest : PyTestCase() { assertCompletionContains("\"x\"", "\"y\"") } + fun testEmptyLiteralsInMethodCall() { + assertCompletionContains("\"name\"", "\"age\"") + } + + fun testEmptyLiteralsInMethodCallWithKeywordArgument() { + assertCompletionContains("\"name\"", "\"age\"") + } + fun testEmptyLiteralsInCallExpressionsWithQuotes() { assertCompletionContains("x", "y") }