PY-16553 Simpler solution - add missing comma through PSI

This commit is contained in:
Mikhail Golubev
2016-05-02 20:32:55 +03:00
parent 93f581a528
commit 3050bb0b98
5 changed files with 51 additions and 49 deletions

View File

@@ -90,27 +90,39 @@ public abstract class PyBaseConvertCollectionLiteralIntention extends BaseIntent
final PySequenceExpression literal = findCollectionLiteralUnderCaret(editor, file);
assert literal != null;
final PsiElement replacedElement;
if (literal instanceof PyTupleExpression && literal.getParent() instanceof PyParenthesizedExpression) {
replacedElement = literal.getParent();
}
else {
replacedElement = literal;
}
final PsiElement replacedElement = wrapCollection(literal);
final PsiElement copy = prepareOriginalElementCopy(replacedElement.copy());
final TextRange contentRange = getRangeOfContentWithoutBraces(replacedElement);
final TextRange contentRange = getRangeOfContentWithoutBraces(copy);
final String contentToWrap = contentRange.substring(copy.getText());
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
final String contentToWrap = prepareContent(replacedElement, literal, contentRange);
final PyExpression newLiteral = elementGenerator.createExpressionFromText(LanguageLevel.forElement(file),
myLeftBrace + contentToWrap + myRightBrace);
replacedElement.replace(newLiteral);
}
@NotNull
protected String prepareContent(@NotNull PsiElement replacedElement,
@NotNull PySequenceExpression collection,
@NotNull TextRange contentRange) {
return contentRange.substring(replacedElement.getText());
protected PsiElement prepareOriginalElementCopy(@NotNull PsiElement copy) {
return copy;
}
@NotNull
protected static PySequenceExpression unwrapCollection(@NotNull PsiElement literal) {
final PyParenthesizedExpression parenthesizedExpression = as(literal, PyParenthesizedExpression.class);
if (parenthesizedExpression != null) {
final PyExpression containedExpression = parenthesizedExpression.getContainedExpression();
assert containedExpression != null;
return (PyTupleExpression)containedExpression;
}
return (PySequenceExpression)literal;
}
@NotNull
protected static PsiElement wrapCollection(@NotNull PySequenceExpression literal) {
if (literal instanceof PyTupleExpression && literal.getParent() instanceof PyParenthesizedExpression) {
return literal.getParent();
}
return literal;
}
@NotNull

View File

@@ -15,10 +15,10 @@
*/
package com.jetbrains.python.codeInsight.intentions;
import com.intellij.openapi.util.TextRange;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PySequenceExpression;
import com.jetbrains.python.psi.PyTupleExpression;
@@ -33,43 +33,20 @@ public class PyConvertLiteralToTupleIntention extends PyBaseConvertCollectionLit
super(PyTupleExpression.class, "tuple", "(", ")");
}
@NotNull
@Override
protected String prepareContent(@NotNull PsiElement replacedElement,
@NotNull PySequenceExpression collection,
@NotNull TextRange contentRange) {
assert !(collection instanceof PyTupleExpression);
final String contentWithoutBraces = super.prepareContent(replacedElement, collection, contentRange);
final PyExpression[] elements = collection.getElements();
if (elements.length != 1) {
return contentWithoutBraces;
}
final PsiElement lastChild = collection.getLastChild();
boolean endsWithComma = false;
final IElementType lastChildType = lastChild.getNode().getElementType();
if (lastChildType == PyTokenTypes.COMMA) {
endsWithComma = true;
}
else if (PyTokenTypes.CLOSE_BRACES.contains(lastChildType)) {
final PsiElement prev = PyPsiUtils.getPrevNonWhitespaceSibling(lastChild);
if (prev != null && prev.getNode().getElementType() == PyTokenTypes.COMMA) {
endsWithComma = true;
protected PsiElement prepareOriginalElementCopy(@NotNull PsiElement copy) {
final PySequenceExpression sequenceExpression = unwrapCollection(copy);
final PyExpression[] elements = sequenceExpression.getElements();
if (elements.length == 1) {
final PyExpression onlyElement = elements[0];
final PsiElement next = PyPsiUtils.getNextNonCommentSibling(onlyElement, true);
if (next != null && next.getNode().getElementType() != PyTokenTypes.COMMA) {
final PyElementGenerator generator = PyElementGenerator.getInstance(copy.getProject());
final ASTNode anchor = onlyElement.getNode().getTreeNext();
sequenceExpression.getNode().addChild(generator.createComma(), anchor);
}
}
if (endsWithComma) {
return contentWithoutBraces;
}
final PyExpression singleElem = elements[0];
final int commaOffset = singleElem.getTextRange().getEndOffset() - replacedElement.getTextRange().getStartOffset();
final String wholeText = replacedElement.getText();
return wholeText.substring(contentRange.getStartOffset(), commaOffset) +
"," +
wholeText.substring(commaOffset, contentRange.getEndOffset());
return copy;
}
}

View File

@@ -123,4 +123,9 @@ public class PyConvertCollectionLiteralIntentionTest extends PyIntentionTestCase
public void testConvertOneElementListWithCommentToTuple() {
doIntentionTest(CONVERT_LIST_TO_TUPLE);
}
// PY-16553
public void testConvertOneElementListWithCommaAfterCommentToTuple() {
doIntentionTest(CONVERT_LIST_TO_TUPLE);
}
}