mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-72661 Literal completion inside nested parenthesis
GitOrigin-RevId: 14f18efcbaa520ac36ddd4892b774ed60a01cfdc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3d3aefb69d
commit
ee91d6a211
+1
-1
@@ -53,7 +53,7 @@ private class DictLiteralCompletionProvider : CompletionProvider<CompletionParam
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(originalElement.project, originalElement.containingFile)
|
||||
val actualType = typeEvalContext.getType(possibleSequenceExpr)
|
||||
val quote = getForcedQuote(possibleSequenceExpr, originalElement)
|
||||
PyCallExpressionHelper.getMappedParameters(possibleSequenceExpr, PyResolveContext.defaultContext(typeEvalContext)).forEach {
|
||||
PyCallExpressionHelper.getMappedParameters(possibleSequenceExpr, PyResolveContext.defaultContext(typeEvalContext))?.forEach {
|
||||
addCompletionForTypedDictKeys(it.getType(typeEvalContext), actualType, result, quote)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-17
@@ -4,7 +4,6 @@ import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.completion.ml.MLRankingIgnorable
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.patterns.PlatformPatterns.psiElement
|
||||
import com.intellij.patterns.StandardPatterns.or
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.ui.IconManager
|
||||
@@ -12,6 +11,7 @@ import com.intellij.ui.PlatformIcons
|
||||
import com.intellij.util.ProcessingContext
|
||||
import com.jetbrains.python.psi.*
|
||||
import com.jetbrains.python.psi.impl.PyCallExpressionHelper
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext
|
||||
import com.jetbrains.python.psi.types.PyLiteralType
|
||||
import com.jetbrains.python.psi.types.PyType
|
||||
@@ -20,16 +20,7 @@ import com.jetbrains.python.psi.types.TypeEvalContext
|
||||
|
||||
class PyLiteralTypeCompletionContributor : CompletionContributor() {
|
||||
init {
|
||||
extend(
|
||||
CompletionType.BASIC,
|
||||
or(
|
||||
psiElement().withSuperParent(2, PyKeywordArgument::class.java),
|
||||
psiElement().withSuperParent(2, PyArgumentList::class.java),
|
||||
psiElement().withSuperParent(2, PySubscriptionExpression::class.java),
|
||||
psiElement().inside(PyAssignmentStatement::class.java),
|
||||
),
|
||||
PyLiteralTypeCompletionProvider()
|
||||
)
|
||||
extend(CompletionType.BASIC, psiElement(), PyLiteralTypeCompletionProvider())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +29,9 @@ private class PyLiteralTypeCompletionProvider : CompletionProvider<CompletionPar
|
||||
val position = parameters.position.parent as? PyExpression ?: return
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(position.project, position.containingFile)
|
||||
|
||||
val callSiteExpr = PsiTreeUtil.getParentOfType(position, PyCallSiteExpression::class.java)
|
||||
if (callSiteExpr != null) {
|
||||
val types = PyCallExpressionHelper
|
||||
.getMappedParameters(position, PyResolveContext.defaultContext(typeEvalContext))
|
||||
.mapNotNull { it.getArgumentType(typeEvalContext) }
|
||||
val mappedParameters = PyCallExpressionHelper.getMappedParameters(position, PyResolveContext.defaultContext(typeEvalContext))
|
||||
if (mappedParameters != null) {
|
||||
val types = mappedParameters.mapNotNull { it.getArgumentType(typeEvalContext) }
|
||||
addToResult(position, types, result)
|
||||
return
|
||||
}
|
||||
@@ -51,11 +40,12 @@ private class PyLiteralTypeCompletionProvider : CompletionProvider<CompletionPar
|
||||
PyParenthesizedExpression::class.java,
|
||||
PyTupleExpression::class.java) as? PyAssignmentStatement
|
||||
if (assignmentStatement != null) {
|
||||
val mapping = assignmentStatement.targetsToValuesMapping.find { it.second === position }
|
||||
val mapping = assignmentStatement.targetsToValuesMapping.find { PyPsiUtils.flattenParens(it.second) === position }
|
||||
if (mapping != null) {
|
||||
val type = typeEvalContext.getType(mapping.first)
|
||||
addToResult(position, listOfNotNull(type), result)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -755,14 +755,15 @@ public final class PyCallExpressionHelper {
|
||||
* {@code argument} can be (parenthesized) expression or a value of a {@link PyKeywordArgument}
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NotNull
|
||||
@Nullable
|
||||
public static List<PyCallableParameter> getMappedParameters(@NotNull PyExpression argument,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
while (argument.getParent() instanceof PyParenthesizedExpression parenthesizedExpr) {
|
||||
argument = parenthesizedExpr;
|
||||
}
|
||||
|
||||
if (argument.getParent() instanceof PyKeywordArgument keywordArgument && keywordArgument.getValueExpression() == argument) {
|
||||
if (argument.getParent() instanceof PyKeywordArgument keywordArgument) {
|
||||
assert keywordArgument.getValueExpression() == argument;
|
||||
argument = keywordArgument;
|
||||
}
|
||||
|
||||
@@ -771,7 +772,7 @@ public final class PyCallExpressionHelper {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (!(parent instanceof PyCallSiteExpression callSite)) {
|
||||
return Collections.emptyList();
|
||||
return null;
|
||||
}
|
||||
|
||||
PyExpression finalArgument = argument;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from typing import Literal
|
||||
|
||||
|
||||
item: Literal[Literal[Literal["0", 2], "acc"], "5", None]
|
||||
item=(((<caret>)))
|
||||
@@ -0,0 +1,8 @@
|
||||
from typing import Literal
|
||||
|
||||
|
||||
def f(x, y: Literal[Literal["abb"], "bac"]):
|
||||
pass
|
||||
|
||||
|
||||
f(1, ((("<caret>"))))
|
||||
@@ -0,0 +1,8 @@
|
||||
from typing import Literal
|
||||
|
||||
|
||||
def f(x: Literal[Literal[Literal[1, "-1"], "foo"], "6", None]) -> None:
|
||||
pass
|
||||
|
||||
|
||||
f(x=((((<caret>)))))
|
||||
@@ -0,0 +1,8 @@
|
||||
from typing import Literal
|
||||
|
||||
class A:
|
||||
def __getitem__(self, item: Literal[Literal[Literal["1", "2"], "foo"], "5", None]) -> str:
|
||||
pass
|
||||
|
||||
|
||||
A()[(((("<caret>"))))]
|
||||
@@ -11,18 +11,38 @@ class PyLiteralTypeCompletionTest : PyTestCase() {
|
||||
doTestCompletionVariantsContains("inCallExpression.py", "\"1\"", "\"2\"", "\"foo\"", "\"5\"")
|
||||
}
|
||||
|
||||
// PY-72661
|
||||
fun testNestedParenthesisInCallExpression() {
|
||||
myFixture.testCompletionVariants("nestedParenthesisInCallExpression.py", "abb", "bac")
|
||||
}
|
||||
|
||||
fun testInKeywordArgument() {
|
||||
doTestCompletionVariantsContains("inKeywordArgument.py", "\"3\"", "\"foo\"", "\"5\"")
|
||||
}
|
||||
|
||||
// PY-72661
|
||||
fun testNestedParenthesisInKeywordArgumentValue() {
|
||||
doTestCompletionVariantsContains("nestedParenthesisInKeywordArgumentValue.py", "\"-1\"", "\"foo\"", "\"6\"")
|
||||
}
|
||||
|
||||
fun testInSubscriptionExpression() {
|
||||
doTestCompletionVariantsContains("inSubscriptionExpression.py", "\"1\"", "\"foo\"", "\"5\"")
|
||||
}
|
||||
|
||||
// PY-72661
|
||||
fun testNestedParenthesisInSubscriptionExpression() {
|
||||
myFixture.testCompletionVariants("nestedParenthesisInSubscriptionExpression.py", "1", "2", "foo", "5")
|
||||
}
|
||||
|
||||
fun testInAssigment() {
|
||||
doTestCompletionVariantsContains("inAssignment.py", "\"1\"", "\"3\"", "\"foo\"", "\"5\"")
|
||||
}
|
||||
|
||||
// PY-72661
|
||||
fun testNestedParenthesisInAssigment() {
|
||||
doTestCompletionVariantsContains("nestedParenthesisInAssigment.py", "\"0\"", "\"acc\"", "\"5\"")
|
||||
}
|
||||
|
||||
fun testInDoubleQuotedString() {
|
||||
myFixture.testCompletionVariants("inDoubleQuotedString.py", "bar", "foo")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user