PY-46178 Protect against illegal fragment expression in f-string-like completion

It's not enough to just prepend an arbitrary string with "f" to treat it like
a well-formed f-string. If its part following "IntellijIdeaRulezzz " placeholder
contains special characters, such as "&" in URLs, it can break parsing of
a generated fragment to the extent we are no longer able to recover a string
literal from it (it all gets treated as a single embedded expression).
Forcibly closing a started fragment with "} " seems sufficient to guard against
the subsequent string content.

GitOrigin-RevId: fe682511475b800f013ace5e6e52fca9286cd418
This commit is contained in:
Mikhail Golubev
2021-03-16 21:44:20 +03:00
committed by intellij-monorepo-bot
parent a8a5d62e3c
commit b3daaed02f
3 changed files with 16 additions and 2 deletions

View File

@@ -3,7 +3,6 @@ package com.jetbrains.python.codeInsight.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.editor.Document;
import com.intellij.patterns.PsiElementPattern;
import com.intellij.psi.PsiReference;
@@ -72,7 +71,12 @@ public class PyFStringLikeCompletionContributor extends CompletionContributor {
if (prefixCannotStartReference) {
return;
}
PyExpression fString = PyUtil.createExpressionFromFragment("f" + stringElemText, stringLiteral.getParent());
String fStringText = new StringBuilder()
.append("f").append(stringElemText)
.insert(relOffset + 1 + CompletionUtilCore.DUMMY_IDENTIFIER.length(), "} ")
.toString();
PyExpression fString = PyUtil.createExpressionFromFragment(fStringText, stringLiteral.getParent());
assert fString != null;
PsiReference reference = fString.findReferenceAt(relOffset + 1);
if (reference == null) {

View File

@@ -0,0 +1,2 @@
city = "spb"
foo = "https://weather.talkpython.fm/api/weather?city={<caret>&state=&country=&units=imperial"

View File

@@ -468,6 +468,14 @@ public class Py3CompletionTest extends PyTestCase {
assertTrue(ContainerUtil.exists(variants, v -> v.getLookupString().equals("my_expr")));
}
// PY-46178
public void testFStringLikeCompletionInsideUrl() {
final String testName = getTestName(true);
myFixture.configureByFile(testName + ".py");
myFixture.completeBasic();
assertContainsElements(myFixture.getLookupElementStrings(), "city");
}
// PY-46056
public void testImportCompletionHintForSameDirectoryModuleInOrdinaryPackage() {
doTestVariantTailText("ordinaryPackage/sample.py", "logging", null);