mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
Conflicts: python/community/psi-api/src/com/jetbrains/python/PyNames.java
This commit is contained in:
@@ -119,6 +119,8 @@ public class PyNames {
|
||||
public static final String COLLECTIONS = "collections";
|
||||
public static final String COLLECTIONS_NAMEDTUPLE = COLLECTIONS + "." + NAMEDTUPLE;
|
||||
|
||||
public static final String FORMAT = "format";
|
||||
|
||||
public static final String ABSTRACTMETHOD = "abc.abstractmethod";
|
||||
public static final String ABSTRACTPROPERTY = "abc.abstractproperty";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<id>org.jetbrains.plugins.rest</id>
|
||||
<description>This plugin enables support for reStructuredText files (*.rst)</description>
|
||||
<vendor>JetBrains</vendor>
|
||||
<version>130.SNAPSHOT</version>
|
||||
<version>132.SNAPSHOT</version>
|
||||
<idea-version since-build="130.1" until-build="133.0"/>
|
||||
<depends>com.intellij.modules.lang</depends>
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.jetbrains.python.codeInsight;
|
||||
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.jetbrains.python.inspections.PyStringFormatParser.*;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyInjectionUtil {
|
||||
private PyInjectionUtil() {}
|
||||
|
||||
/**
|
||||
* Returns true if the element is the largest expression that represents a string literal, possibly with concatenation, parentheses,
|
||||
* or formatting.
|
||||
*/
|
||||
public static boolean isLargestStringLiteral(@NotNull PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
return isStringLiteralPart(element) && (parent == null || !isStringLiteralPart(parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers language injections in the given registrar for the specified string literal element or its ancestor that contains
|
||||
* string concatenations or formatting.
|
||||
*/
|
||||
public static void registerStringLiteralInjection(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar) {
|
||||
processStringLiteral(element, registrar, "", "", Formatting.NONE);
|
||||
}
|
||||
|
||||
private static boolean isStringLiteralPart(@NotNull PsiElement element) {
|
||||
if (element instanceof PyStringLiteralExpression) {
|
||||
return true;
|
||||
}
|
||||
else if (element instanceof PyParenthesizedExpression) {
|
||||
final PyExpression contained = ((PyParenthesizedExpression)element).getContainedExpression();
|
||||
return contained != null && isStringLiteralPart(contained);
|
||||
}
|
||||
else if (element instanceof PyBinaryExpression) {
|
||||
final PyBinaryExpression expr = (PyBinaryExpression)element;
|
||||
final PyExpression left = expr.getLeftExpression();
|
||||
final PyExpression right = expr.getRightExpression();
|
||||
return (expr.isOperator("+") && (isStringLiteralPart(left) || right != null && isStringLiteralPart(right))) ||
|
||||
expr.isOperator("%") && isStringLiteralPart(left);
|
||||
}
|
||||
else if (element instanceof PyCallExpression) {
|
||||
final PyExpression qualifier = getFormatCallQualifier((PyCallExpression)element);
|
||||
return qualifier != null && isStringLiteralPart(qualifier);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyExpression getFormatCallQualifier(@NotNull PyCallExpression element) {
|
||||
final PyExpression callee = element.getCallee();
|
||||
if (callee instanceof PyQualifiedExpression) {
|
||||
final PyQualifiedExpression qualifiedExpr = (PyQualifiedExpression)callee;
|
||||
final PyExpression qualifier = qualifiedExpr.getQualifier();
|
||||
if (qualifier != null && PyNames.FORMAT.equals(qualifiedExpr.getReferencedName())) {
|
||||
return qualifier;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void processStringLiteral(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar, @NotNull String prefix,
|
||||
@NotNull String suffix, @NotNull Formatting formatting) {
|
||||
final String missingValue = "missing";
|
||||
if (element instanceof PyStringLiteralExpression) {
|
||||
final PyStringLiteralExpression expr = (PyStringLiteralExpression)element;
|
||||
final List<TextRange> ranges = expr.getStringValueTextRanges();
|
||||
final String text = expr.getText();
|
||||
for (TextRange range : ranges) {
|
||||
if (formatting != Formatting.NONE) {
|
||||
final String part = range.substring(text);
|
||||
final List<FormatStringChunk> chunks = formatting == Formatting.NEW_STYLE ? parseNewStyleFormat(part) : parsePercentFormat(part);
|
||||
for (int i = 0; i < chunks.size(); i++) {
|
||||
final FormatStringChunk chunk = chunks.get(i);
|
||||
if (chunk instanceof ConstantChunk) {
|
||||
final int nextIndex = i + 1;
|
||||
final String chunkPrefix = i == 1 && chunks.get(0) instanceof SubstitutionChunk ? missingValue : "";
|
||||
final String chunkSuffix = nextIndex < chunks.size() &&
|
||||
chunks.get(nextIndex) instanceof SubstitutionChunk ? missingValue : "";
|
||||
final TextRange chunkRange = chunk.getTextRange().shiftRight(range.getStartOffset());
|
||||
registrar.addPlace(chunkPrefix, chunkSuffix, expr, chunkRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
registrar.addPlace(prefix, suffix, expr, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyParenthesizedExpression) {
|
||||
final PyExpression contained = ((PyParenthesizedExpression)element).getContainedExpression();
|
||||
if (contained != null) {
|
||||
processStringLiteral(contained, registrar, prefix, suffix, formatting);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyBinaryExpression) {
|
||||
final PyBinaryExpression expr = (PyBinaryExpression)element;
|
||||
final PyExpression left = expr.getLeftExpression();
|
||||
final PyExpression right = expr.getRightExpression();
|
||||
final boolean isLeftString = isStringLiteralPart(left);
|
||||
if (expr.isOperator("+")) {
|
||||
final boolean isRightString = right != null && isStringLiteralPart(right);
|
||||
if (isLeftString) {
|
||||
processStringLiteral(left, registrar, prefix, isRightString ? "" : missingValue, formatting);
|
||||
}
|
||||
if (isRightString) {
|
||||
processStringLiteral(right, registrar, isLeftString ? "" : missingValue, suffix, formatting);
|
||||
}
|
||||
}
|
||||
else if (expr.isOperator("%")) {
|
||||
processStringLiteral(left, registrar, prefix, suffix, Formatting.PERCENT);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyCallExpression) {
|
||||
final PyExpression qualifier = getFormatCallQualifier((PyCallExpression)element);
|
||||
if (qualifier != null) {
|
||||
processStringLiteral(qualifier, registrar, prefix, suffix, Formatting.NEW_STYLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum Formatting {
|
||||
NONE,
|
||||
PERCENT,
|
||||
NEW_STYLE
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@ package com.jetbrains.python.codeInsight.regexp;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.injection.MultiHostInjector;
|
||||
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.codeInsight.PyInjectionUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -51,7 +51,7 @@ public class PythonRegexpInjector implements MultiHostInjector {
|
||||
@Override
|
||||
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
|
||||
final PsiElement contextParent = context.getParent();
|
||||
if (isStringLiteral(context) && contextParent instanceof PyArgumentList) {
|
||||
if (PyInjectionUtil.isLargestStringLiteral(context) && contextParent instanceof PyArgumentList) {
|
||||
final PyExpression[] args = ((PyArgumentList)contextParent).getArguments();
|
||||
int index = ArrayUtil.indexOf(args, context);
|
||||
PyCallExpression call = PsiTreeUtil.getParentOfType(context, PyCallExpression.class);
|
||||
@@ -64,74 +64,20 @@ public class PythonRegexpInjector implements MultiHostInjector {
|
||||
if (element != null && element.getContainingFile().getName().equals("re.py") && isRegexpMethod(element, index)) {
|
||||
final Language language = isVerbose(call) ? PythonVerboseRegexpLanguage.INSTANCE : PythonRegexpLanguage.INSTANCE;
|
||||
registrar.startInjecting(language);
|
||||
processStringLiteral(context, registrar);
|
||||
PyInjectionUtil.registerStringLiteralInjection(context, registrar);
|
||||
registrar.doneInjecting();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean isStringLiteral(@NotNull PsiElement element) {
|
||||
if (element instanceof PyStringLiteralExpression) {
|
||||
return true;
|
||||
}
|
||||
else if (element instanceof PyParenthesizedExpression) {
|
||||
final PyExpression contained = ((PyParenthesizedExpression)element).getContainedExpression();
|
||||
return contained != null && isStringLiteral(contained);
|
||||
}
|
||||
else if (element instanceof PyBinaryExpression) {
|
||||
final PyBinaryExpression expr = (PyBinaryExpression)element;
|
||||
final PyExpression left = expr.getLeftExpression();
|
||||
final PyExpression right = expr.getRightExpression();
|
||||
return expr.isOperator("+") && (isStringLiteral(left) || right != null && isStringLiteral(right));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void processStringLiteral(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar) {
|
||||
processStringLiteral(element, registrar, "", "");
|
||||
}
|
||||
|
||||
private static void processStringLiteral(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar, @NotNull String prefix,
|
||||
@NotNull String suffix) {
|
||||
final String missingValue = "missing";
|
||||
if (element instanceof PyStringLiteralExpression) {
|
||||
final PyStringLiteralExpression expr = (PyStringLiteralExpression)element;
|
||||
final List<TextRange> ranges = expr.getStringValueTextRanges();
|
||||
for (TextRange range : ranges) {
|
||||
registrar.addPlace(prefix, suffix, expr, range);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyParenthesizedExpression) {
|
||||
final PyExpression contained = ((PyParenthesizedExpression)element).getContainedExpression();
|
||||
if (contained != null) {
|
||||
processStringLiteral(contained, registrar, prefix, suffix);
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyBinaryExpression) {
|
||||
final PyBinaryExpression expr = (PyBinaryExpression)element;
|
||||
if (expr.isOperator("+")) {
|
||||
final PyExpression left = expr.getLeftExpression();
|
||||
final PyExpression right = expr.getRightExpression();
|
||||
final boolean isLeftString = isStringLiteral(left);
|
||||
final boolean isRightString = right != null && isStringLiteral(right);
|
||||
if (isLeftString) {
|
||||
processStringLiteral(left, registrar, prefix, isRightString ? "" : missingValue);
|
||||
}
|
||||
if (isRightString) {
|
||||
processStringLiteral(right, registrar, isLeftString ? "" : missingValue, suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
|
||||
return Arrays.asList(PyStringLiteralExpression.class, PyParenthesizedExpression.class, PyBinaryExpression.class);
|
||||
return Arrays.asList(PyStringLiteralExpression.class, PyParenthesizedExpression.class, PyBinaryExpression.class,
|
||||
PyCallExpression.class);
|
||||
}
|
||||
|
||||
private static boolean isVerbose(@NotNull PyCallExpression call) {
|
||||
|
||||
@@ -23,6 +23,9 @@ import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.jetbrains.python.inspections.PyStringFormatParser.filterSubstitutions;
|
||||
import static com.jetbrains.python.inspections.PyStringFormatParser.parsePercentFormat;
|
||||
|
||||
/**
|
||||
* @author Alexey.Ivanov
|
||||
*/
|
||||
@@ -332,8 +335,8 @@ public class PyStringFormatInspection extends PyInspection {
|
||||
}
|
||||
|
||||
private void inspectFormat(@NotNull final PyStringLiteralExpression formatExpression) {
|
||||
PyStringFormatParser parser = new PyStringFormatParser(formatExpression.getStringValue());
|
||||
final List<PyStringFormatParser.SubstitutionChunk> chunks = parser.parseSubstitutions();
|
||||
final String value = formatExpression.getStringValue();
|
||||
final List<PyStringFormatParser.SubstitutionChunk> chunks = filterSubstitutions(parsePercentFormat(value));
|
||||
|
||||
// 1. The '%' character
|
||||
// Skip the first item in the sections, it's always empty
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -145,10 +146,15 @@ public class PyStringFormatParser {
|
||||
private static final String LENGTH_MODIFIERS = "hlL";
|
||||
private static final String VALID_CONVERSION_TYPES = "diouxXeEfFgGcrs";
|
||||
|
||||
public PyStringFormatParser(@NotNull String literal) {
|
||||
private PyStringFormatParser(@NotNull String literal) {
|
||||
myLiteral = literal;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<FormatStringChunk> parsePercentFormat(@NotNull String s) {
|
||||
return new PyStringFormatParser(s).parse();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<FormatStringChunk> parseNewStyleFormat(@NotNull String s) {
|
||||
final List<FormatStringChunk> results = new ArrayList<FormatStringChunk>();
|
||||
@@ -191,13 +197,13 @@ public class PyStringFormatParser {
|
||||
pos = next + 1;
|
||||
}
|
||||
if (pos < n) {
|
||||
results.add(new ConstantChunk(pos, n + 1));
|
||||
results.add(new ConstantChunk(pos, n));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<FormatStringChunk> parse() {
|
||||
private List<FormatStringChunk> parse() {
|
||||
myPos = 0;
|
||||
while(myPos < myLiteral.length()) {
|
||||
int next = myLiteral.indexOf('%', myPos);
|
||||
@@ -277,11 +283,6 @@ public class PyStringFormatParser {
|
||||
return myLiteral.substring(flagStart, myPos);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<SubstitutionChunk> parseSubstitutions() {
|
||||
return filterSubstitutions(parse());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<SubstitutionChunk> filterSubstitutions(@NotNull List<FormatStringChunk> chunks) {
|
||||
final List<SubstitutionChunk> results = new ArrayList<SubstitutionChunk>();
|
||||
@@ -353,7 +354,7 @@ public class PyStringFormatParser {
|
||||
if (parent instanceof PyQualifiedExpression) {
|
||||
final PyQualifiedExpression qualifiedExpr = (PyQualifiedExpression)parent;
|
||||
final String name = qualifiedExpr.getReferencedName();
|
||||
if ("format".equals(name)) {
|
||||
if (PyNames.FORMAT.equals(name)) {
|
||||
final PsiElement parent2 = qualifiedExpr.getParent();
|
||||
if (parent2 instanceof PyCallExpression) {
|
||||
final PyCallExpression callExpr = (PyCallExpression)parent2;
|
||||
|
||||
@@ -24,6 +24,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
import static com.jetbrains.python.PyTokenTypes.*;
|
||||
import static com.jetbrains.python.inspections.PyStringFormatParser.filterSubstitutions;
|
||||
import static com.jetbrains.python.inspections.PyStringFormatParser.parseNewStyleFormat;
|
||||
import static com.jetbrains.python.inspections.PyStringFormatParser.parsePercentFormat;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
@@ -94,10 +97,10 @@ public class PyReplaceExpressionUtil implements PyElementTypes {
|
||||
|
||||
final List<PyStringFormatParser.SubstitutionChunk> substitutions;
|
||||
if (newStyleFormatValue != null) {
|
||||
substitutions = PyStringFormatParser.filterSubstitutions(PyStringFormatParser.parseNewStyleFormat(fullText));
|
||||
substitutions = filterSubstitutions(parseNewStyleFormat(fullText));
|
||||
}
|
||||
else {
|
||||
substitutions = new PyStringFormatParser(fullText).parseSubstitutions();
|
||||
substitutions = filterSubstitutions(parsePercentFormat(fullText));
|
||||
}
|
||||
final boolean hasSubstitutions = substitutions.size() > 0;
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonStringUtil;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.inspections.PyStringFormatParser;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.types.PyNoneType;
|
||||
@@ -306,7 +305,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
|
||||
}
|
||||
|
||||
private boolean breaksStringFormatting(@NotNull String s, @NotNull TextRange range) {
|
||||
return breaksRanges(substitutionsToRanges(new PyStringFormatParser(s).parseSubstitutions()), range);
|
||||
return breaksRanges(substitutionsToRanges(filterSubstitutions(parsePercentFormat(s))), range);
|
||||
}
|
||||
|
||||
private boolean breaksNewStyleStringFormatting(@NotNull String s, @NotNull TextRange range) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.jetbrains.python.sdk;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
|
||||
@@ -130,7 +131,9 @@ public class InterpreterPathChooser extends BaseListPopupStep<String> {
|
||||
remoteInterpreterManager.addRemoteSdk(myProject, myOwnerComponent, Lists.newArrayList(myExistingSdks), myCallback);
|
||||
}
|
||||
else {
|
||||
Messages.showErrorDialog("The Remote Hosts Access plugin is missing. Please enable the plugin in Settings | Plugins.", "Add Remote Interpreter");
|
||||
Messages.showErrorDialog("The Remote Hosts Access plugin is missing. Please enable the plugin in " +
|
||||
ShowSettingsUtil.getSettingsMenuName() +
|
||||
" | Plugins.", "Add Remote Interpreter");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ public class PythonSpellcheckerStrategy extends SpellcheckingStrategy {
|
||||
@Override
|
||||
public void tokenize(@NotNull PyStringLiteralExpression element, TokenConsumer consumer) {
|
||||
String stringValue = element.getStringValue();
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser(stringValue).parse();
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = PyStringFormatParser.parsePercentFormat(stringValue);
|
||||
Splitter splitter = PlainTextSplitter.getInstance();
|
||||
for (PyStringFormatParser.FormatStringChunk chunk : chunks) {
|
||||
if (chunk instanceof PyStringFormatParser.ConstantChunk) {
|
||||
|
||||
@@ -111,6 +111,30 @@ public class PyRegexpTest extends PyTestCase {
|
||||
".*(missing)missing");
|
||||
}
|
||||
|
||||
public void testPercentFormattingRegexpAutoInjection() {
|
||||
doTestInjectedText("import re \n" +
|
||||
"\n" +
|
||||
"def f(x, y):\n" +
|
||||
" re.search('<caret>.*%s-%d' % (x, y), 'foo')\n",
|
||||
".*missing-missing");
|
||||
}
|
||||
|
||||
public void testNewStyleFormattingRegexpAutoInjection() {
|
||||
doTestInjectedText("import re\n" +
|
||||
"\n" +
|
||||
"def f(x, y):\n" +
|
||||
" re.search('<caret>.*{foo}-{}'.format(x, foo=y), 'foo')\n",
|
||||
".*missing-missing");
|
||||
}
|
||||
|
||||
public void testNewStyleFormattingEndsWithConstant() {
|
||||
doTestInjectedText("import re\n" +
|
||||
"\n" +
|
||||
"def f(**kwargs):" +
|
||||
" re.search('<caret>(foo{bar}baz$)'.format(**kwargs), 'foo')\n",
|
||||
"(foomissingbaz$)");
|
||||
}
|
||||
|
||||
private void doTestInjectedText(@NotNull String text, @NotNull String expected) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.jetbrains.python.inspections.PyStringFormatParser;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.List;
|
||||
@@ -13,7 +12,7 @@ import static com.jetbrains.python.inspections.PyStringFormatParser.*;
|
||||
*/
|
||||
public class PyStringFormatParserTest extends TestCase {
|
||||
public void testSimple() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("abc").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("abc");
|
||||
assertEquals(1, chunks.size());
|
||||
assertConstant(chunks.get(0), 0, 3);
|
||||
}
|
||||
@@ -25,13 +24,13 @@ public class PyStringFormatParserTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testDoublePercent() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("abc%%def").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("abc%%def");
|
||||
assertEquals(1, chunks.size());
|
||||
assertConstant(chunks.get(0), 0, 8);
|
||||
}
|
||||
|
||||
public void testFormat() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%s").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%s");
|
||||
assertEquals(1, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals(0, chunk.getStartIndex());
|
||||
@@ -40,13 +39,13 @@ public class PyStringFormatParserTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testSubstitutionAfterFormat() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("Hello, %s").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("Hello, %s");
|
||||
assertEquals(2, chunks.size());
|
||||
assertConstant(chunks.get(0), 0, 7);
|
||||
}
|
||||
|
||||
public void testMappingKey() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%(language)s").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%(language)s");
|
||||
assertEquals(1, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals("language", chunk.getMappingKey());
|
||||
@@ -54,35 +53,35 @@ public class PyStringFormatParserTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testConversionFlags() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%#0d").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%#0d");
|
||||
assertEquals(1, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals("#0", chunk.getConversionFlags());
|
||||
}
|
||||
|
||||
public void testWidth() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%345d").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%345d");
|
||||
assertEquals(1, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals("345", chunk.getWidth());
|
||||
}
|
||||
|
||||
public void testPrecision() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%.2d").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%.2d");
|
||||
assertEquals(1, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals("2", chunk.getPrecision());
|
||||
}
|
||||
|
||||
public void testLengthModifier() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%ld").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%ld");
|
||||
assertEquals(1, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals('l', chunk.getLengthModifier());
|
||||
}
|
||||
|
||||
public void testDoubleAsterisk() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%**d").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%**d");
|
||||
assertEquals(2, chunks.size());
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals(2, chunk.getEndIndex());
|
||||
@@ -90,7 +89,7 @@ public class PyStringFormatParserTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testUnclosedMapping() {
|
||||
List<PyStringFormatParser.FormatStringChunk> chunks = new PyStringFormatParser("%(name1s").parse();
|
||||
List<FormatStringChunk> chunks = parsePercentFormat("%(name1s");
|
||||
SubstitutionChunk chunk = (SubstitutionChunk) chunks.get(0);
|
||||
assertEquals("name1s", chunk.getMappingKey());
|
||||
assertTrue(chunk.isUnclosedMapping());
|
||||
@@ -126,4 +125,10 @@ public class PyStringFormatParserTest extends TestCase {
|
||||
assertEquals(1, chunks.size());
|
||||
assertEquals(TextRange.create(1, 4), chunks.get(0).getTextRange());
|
||||
}
|
||||
|
||||
public void testNewStyleConstant() {
|
||||
List<FormatStringChunk> chunks = parseNewStyleFormat("a");
|
||||
assertEquals(1, chunks.size());
|
||||
assertConstant(chunks.get(0), 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user