PY-31442 Get rid of ubiquitous usages of PyStringLiteralExpressionImpl#getNoteTextRange

This commit is contained in:
Mikhail Golubev
2018-10-01 12:46:41 +03:00
parent 79189b4f5e
commit d87b2134f8
7 changed files with 45 additions and 35 deletions
@@ -18,7 +18,7 @@ package com.jetbrains.python.codeInsight.fstrings;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
import com.jetbrains.python.psi.PyStringLiteralUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -44,7 +44,7 @@ public class FStringParser {
private FStringParser(@NotNull String nodeText) {
myNodeText = nodeText;
myNodeContentRange = PyStringLiteralExpressionImpl.getNodeTextRange(myNodeText);
myNodeContentRange = PyStringLiteralUtil.getContentRange(myNodeText);
}
private void parseTopLevel() {
@@ -32,7 +32,6 @@ import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
import com.jetbrains.python.toolbox.Substring;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -135,7 +134,7 @@ public class DocStringUtil {
@NotNull
private static Substring stripPrefixAndQuotes(@NotNull String text) {
final TextRange contentRange = PyStringLiteralExpressionImpl.getNodeTextRange(text);
final TextRange contentRange = PyStringLiteralUtil.getContentRange(text);
return new Substring(text, contentRange.getStartOffset(), contentRange.getEndOffset());
}
@@ -17,7 +17,7 @@ package com.jetbrains.python.inspections;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
import com.jetbrains.python.psi.PyStringLiteralUtil;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -79,7 +79,7 @@ public class PyNewStyleStringFormatParser {
private PyNewStyleStringFormatParser(@NotNull String nodeText) {
myNodeText = nodeText;
myNodeContentRange = PyStringLiteralExpressionImpl.getNodeTextRange(nodeText);
myNodeContentRange = PyStringLiteralUtil.getContentRange(nodeText);
}
private void parseTopLevel() {
@@ -16,6 +16,7 @@
package com.jetbrains.python.psi;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
@@ -41,6 +42,8 @@ public class PyStringLiteralUtil {
public static final int MAX_PREFIX_LENGTH = 3;
private static final ImmutableList<String> QUOTES = ImmutableList.of("'''", "\"\"\"", "'", "\"");
private static final Logger LOG = Logger.getInstance(PyStringLiteralUtil.class);
private PyStringLiteralUtil() {
}
@@ -89,15 +92,21 @@ public class PyStringLiteralUtil {
}
/**
* Handles unicode and raw strings
*
* @param text
* @return open and close quote (including raw/unicode prefixes), null if no quotes present in string
* 'string' -> (', ')
* UR"unicode raw string" -> (UR", ")
* Returns a pair where the first element is the prefix combined with the opening quote and the second is the closing quote.
* <p>
* If the given string literal is not properly quoted, e.g. the closing quote has fewer quotes as opposed to the
* opening one, or it's missing altogether this method returns null.
* <p>
* Examples:
* <pre>
* ur"foo" -> ("ur, ")
* ur'bar -> null
* """baz""" -> (""", """)
* '''quux' -> null
* </pre>
*/
@Nullable
public static Pair<String, String> getQuotes(@NotNull final String text) {
public static Pair<String, String> getQuotes(@NotNull String text) {
final String prefix = getPrefix(text);
final String mainText = text.substring(prefix.length());
for (String quote : QUOTES) {
@@ -109,6 +118,28 @@ public class PyStringLiteralUtil {
return null;
}
/**
* Returns the range of the string literal text between the opening quote and the closing one.
* If the closing quote is either missing or mismatched, this range spans until the end of the literal.
*/
@NotNull
public static TextRange getContentRange(@NotNull String text) {
LOG.assertTrue(isStringLiteralToken(text), "Text of a single string literal node expected: " + text);
int startOffset = getPrefixLength(text);
int delimiterLength = 1;
final String afterPrefix = text.substring(startOffset);
if (afterPrefix.startsWith("\"\"\"") || afterPrefix.startsWith("'''")) {
delimiterLength = 3;
}
final String delimiter = text.substring(startOffset, startOffset + delimiterLength);
startOffset += delimiterLength;
int endOffset = text.length();
if (text.substring(startOffset).endsWith(delimiter)) {
endOffset -= delimiterLength;
}
return new TextRange(startOffset, endOffset);
}
/**
* Finds the end offset of the string prefix starting from {@code startOffset} in the given char sequence.
* String prefix may contain only up to {@link #MAX_PREFIX_LENGTH} characters from {@link #PREFIX_CHARACTERS}
@@ -1921,7 +1921,7 @@ public class PyUtil {
final String nodeText = node.getText();
final int prefixLength = PyStringLiteralUtil.getPrefixLength(nodeText);
myPrefix = nodeText.substring(0, prefixLength);
myContentRange = PyStringLiteralExpressionImpl.getNodeTextRange(nodeText);
myContentRange = PyStringLiteralUtil.getContentRange(nodeText);
myQuote = nodeText.substring(prefixLength, myContentRange.getStartOffset());
}
@@ -55,7 +55,7 @@ public class PyLiteralStringNodeImpl extends LeafPsiElement implements PyLiteral
@NotNull
@Override
public TextRange getContentRange() {
return PyStringLiteralExpressionImpl.getNodeTextRange(getText());
return PyStringLiteralUtil.getContentRange(getText());
}
@NotNull
@@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
@@ -51,7 +50,6 @@ import java.util.EnumSet;
import java.util.List;
public class PyStringLiteralExpressionImpl extends PyElementImpl implements PyStringLiteralExpression, RegExpLanguageHost, PsiLiteralValue {
private static final Logger LOG = Logger.getInstance(PyStringLiteralExpressionImpl.class);
@Nullable private volatile String myStringValue;
@Nullable private volatile List<TextRange> myValueTextRanges;
@@ -93,24 +91,6 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt
return result;
}
// TODO replace all usages with PyStringLiteralUtil.getStringValue(String)
public static TextRange getNodeTextRange(final String text) {
LOG.assertTrue(PyStringLiteralUtil.isStringLiteralToken(text), "Text of a single string literal node expected: " + text);
int startOffset = PyStringLiteralUtil.getPrefixLength(text);
int delimiterLength = 1;
final String afterPrefix = text.substring(startOffset);
if (afterPrefix.startsWith("\"\"\"") || afterPrefix.startsWith("'''")) {
delimiterLength = 3;
}
final String delimiter = text.substring(startOffset, startOffset + delimiterLength);
startOffset += delimiterLength;
int endOffset = text.length();
if (text.substring(startOffset).endsWith(delimiter)) {
endOffset -= delimiterLength;
}
return new TextRange(startOffset, endOffset);
}
@Override
@NotNull
public List<Pair<TextRange, String>> getDecodedFragments() {