mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-83039 Don't trigger PyLiteralTypeCompletionContributor in cases like x = y.foo<caret>
It should be activated only for the simplest cases when the caret is either inside an immediate string literal or its prefix is an unqualified reference expression. It makes little sense trying to detect if something like the literal string `"y.foobar"` is a possible value for `x`. It's a relatively heavy completion contributor. It starts evaluating the type of `x` flow-sensitively, analyzing all preceding function calls to take into account `NoReturn`. It affects common workflows like typing out `df = pd.` to create a new Pandas dataframe. GitOrigin-RevId: f17fe2ce86ee100a3480a574c7f57a1bd67ec2d8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f7b08e1c3d
commit
6ad3c2af62
+19
@@ -18,6 +18,24 @@ import com.jetbrains.python.psi.types.PyType
|
||||
import com.jetbrains.python.psi.types.PyTypeUtil
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext
|
||||
|
||||
/**
|
||||
* Provides literal type variants in the following cases:
|
||||
* ```python
|
||||
* x: Literal["foo", "bar"]
|
||||
* x = <caret>
|
||||
* x = fo<caret>
|
||||
* x = "fo<caret>"
|
||||
* ```
|
||||
*
|
||||
* or
|
||||
*
|
||||
* ```python
|
||||
* def f(x: Literal["foo", "bar"]): ...
|
||||
* f(<caret>)
|
||||
* f(fo<caret>)
|
||||
* f("fo<caret>")
|
||||
* ```
|
||||
*/
|
||||
class PyLiteralTypeCompletionContributor : CompletionContributor() {
|
||||
init {
|
||||
extend(CompletionType.BASIC, psiElement(), PyLiteralTypeCompletionProvider())
|
||||
@@ -27,6 +45,7 @@ class PyLiteralTypeCompletionContributor : CompletionContributor() {
|
||||
private class PyLiteralTypeCompletionProvider : CompletionProvider<CompletionParameters?>() {
|
||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||
val position = parameters.position.parent as? PyExpression ?: return
|
||||
if (!(position is PyStringLiteralExpression || position is PyReferenceExpression && !position.isQualified)) return
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(position.project, position.containingFile)
|
||||
|
||||
val mappedParameters = position.getMappedParameters(PyResolveContext.defaultContext(typeEvalContext))
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
from typing import Literal
|
||||
|
||||
x: Literal["upper", "lower"]
|
||||
y = ""
|
||||
x = y.upp<caret>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
from typing import Literal
|
||||
|
||||
|
||||
def f(x: Literal["upper", "lower"]):
|
||||
pass
|
||||
|
||||
y = ""
|
||||
f(y.up<caret>)
|
||||
@@ -75,6 +75,16 @@ class PyLiteralTypeCompletionTest : PyTestCase() {
|
||||
myFixture.testCompletionVariants("nestedArgumentLists.py")
|
||||
}
|
||||
|
||||
// PY-83039
|
||||
fun testNoLiteralVariantsOnQualifiedReferenceInAssignmentValue() {
|
||||
doTestCompletionVariantsDoesNotContain("noLiteralVariantsOnQualifiedReferenceInAssignmentValue.py", "\"upper\"")
|
||||
}
|
||||
|
||||
// PY-83039
|
||||
fun testNoLiteralVariantsOnQualifiedReferenceInCallArgument() {
|
||||
doTestCompletionVariantsDoesNotContain("noLiteralVariantsOnQualifiedReferenceInCallArgument.py", "\"upper\"")
|
||||
}
|
||||
|
||||
override fun getTestDataPath(): String {
|
||||
return super.getTestDataPath() + "/completion/literalType"
|
||||
}
|
||||
@@ -84,4 +94,10 @@ class PyLiteralTypeCompletionTest : PyTestCase() {
|
||||
assertNotNull(result)
|
||||
assertContainsElements(result!!, *items)
|
||||
}
|
||||
|
||||
private fun doTestCompletionVariantsDoesNotContain(fileBefore: String, vararg items: String) {
|
||||
val result = myFixture.getCompletionVariants(fileBefore)
|
||||
assertNotNull(result)
|
||||
assertDoesntContain(result!!, *items)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user