Move several related methods for navigating PSI and AST trees from PyUtil to PyPsiUtil

This commit is contained in:
Mikhail Golubev
2015-07-03 14:36:59 +03:00
parent d6c167e3f4
commit c47233a435
19 changed files with 159 additions and 119 deletions
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.containers.ContainerUtil;
@@ -58,7 +59,6 @@ public class PyPsiUtils {
/**
* Finds the closest comma after the element skipping any whitespaces in-between.
* @param element
*/
@Nullable
public static PsiElement getPrevComma(@NotNull PsiElement element) {
@@ -66,13 +66,36 @@ public class PyPsiUtils {
return prevNode != null && prevNode.getNode().getElementType() == PyTokenTypes.COMMA ? prevNode : null;
}
/**
* Finds first non-whitespace sibling before given PSI element.
*/
@Nullable
public static PsiElement getPrevNonWhitespaceSibling(@NotNull PsiElement element) {
public static PsiElement getPrevNonWhitespaceSibling(@Nullable PsiElement element) {
return PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace.class);
}
/**
* Finds the closest comma before the element skipping any whitespaces in-between.
* Find first non-whitespace sibling before given AST node.
*/
@Nullable
public static ASTNode getPrevNonWhitespaceSibling(@NotNull ASTNode node) {
return skipSiblingsBackward(node, TokenSet.create(TokenType.WHITE_SPACE));
}
/**
* Find first sibling that is neither comment, nor whitespace before given element or this element itself.
*/
@Nullable
public static PsiElement getFirstNonCommentBefore(@Nullable PsiElement start) {
PsiElement seeker = start;
while (seeker instanceof PsiWhiteSpace || seeker instanceof PsiComment) {
seeker = seeker.getPrevSibling();
}
return seeker;
}
/**
* Finds the closest comma after the element skipping any whitespaces in-between.
*/
@Nullable
public static PsiElement getNextComma(@NotNull PsiElement element) {
@@ -80,11 +103,32 @@ public class PyPsiUtils {
return nextNode != null && nextNode.getNode().getElementType() == PyTokenTypes.COMMA ? nextNode : null;
}
/**
* Finds first non-whitespace sibling after given PSI element.
*/
@Nullable
public static PsiElement getNextNonWhitespaceSibling(@NotNull PsiElement element) {
public static PsiElement getNextNonWhitespaceSibling(@Nullable PsiElement element) {
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class);
}
/**
* Find first non-whitespace sibling after given AST node.
*/
@Nullable
public static ASTNode getNextNonWhitespaceSibling(@NotNull ASTNode after) {
return skipSiblingsForward(after, TokenSet.create(TokenType.WHITE_SPACE));
}
/**
* Find first sibling that is neither comment, nor whitespace after given element or this element itself.
*/
@Nullable
public static PsiElement getFirstNonCommentAfter(@Nullable PsiElement start) {
PsiElement seeker = start;
while (seeker instanceof PsiWhiteSpace || seeker instanceof PsiComment) seeker = seeker.getNextSibling();
return seeker;
}
/**
* Finds the closest comma looking for the next comma first and then for the preceding one.
*/
@@ -94,6 +138,70 @@ public class PyPsiUtils {
return nextComma != null ? nextComma : getPrevComma(element);
}
/**
* Works similarly to {@link PsiTreeUtil#skipSiblingsForward(PsiElement, Class[])}, but for AST nodes.
*/
@Nullable
public static ASTNode skipSiblingsForward(@Nullable ASTNode node, @NotNull TokenSet types) {
if (node == null) {
return null;
}
for (ASTNode next = node.getTreeNext(); next != null; next = next.getTreeNext()) {
if (!types.contains(next.getElementType())) {
return next;
}
}
return null;
}
/**
* Works similarly to {@link PsiTreeUtil#skipSiblingsBackward(PsiElement, Class[])}, but for AST nodes.
*/
@Nullable
public static ASTNode skipSiblingsBackward(@Nullable ASTNode node, @NotNull TokenSet types) {
if (node == null) {
return null;
}
for (ASTNode prev = node.getTreePrev(); prev != null; prev = prev.getTreePrev()) {
if (!types.contains(prev.getElementType())) {
return prev;
}
}
return null;
}
/**
* Returns first child psi element with specified element type or {@code null} if no such element exists.
* Semantically it's the same as {@code getChildByFilter(element, TokenSet.create(type), 0)}.
*
* @param element tree parent node
* @param type element type expected
* @return child element described
*/
@Nullable
public static PsiElement getFirstChildOfType(@NotNull final PsiElement element, @NotNull PyElementType type) {
final ASTNode child = element.getNode().findChildByType(type);
return child != null ? child.getPsi() : null;
}
/**
* Returns child element in the psi tree
*
* @param filter Types of expected child
* @param number number
* @param element tree parent node
* @return PsiElement - child psiElement
*/
@Nullable
public static PsiElement getChildByFilter(@NotNull PsiElement element, @NotNull TokenSet filter, int number) {
final ASTNode node = element.getNode();
if (node != null) {
final ASTNode[] children = node.getChildren(filter);
return (0 <= number && number < children.length) ? children[number].getPsi() : null;
}
return null;
}
public static void addBeforeInParent(@NotNull final PsiElement anchor, @NotNull final PsiElement... newElements) {
final ASTNode anchorNode = anchor.getNode();
LOG.assertTrue(anchorNode != null);
@@ -31,6 +31,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
/**
* Adds appropriate first parameter to a freshly-typed method declaration.
@@ -55,7 +56,7 @@ public class PyMethodNameTypedHandler extends TypedHandlerDelegate {
final ASTNode token_node = token.getNode();
if (token_node != null && token_node.getElementType() == PyTokenTypes.IDENTIFIER) {
PsiElement maybe_def = PyUtil.getFirstNonCommentBefore(token.getPrevSibling());
PsiElement maybe_def = PyPsiUtils.getFirstNonCommentBefore(token.getPrevSibling());
if (maybe_def != null) {
ASTNode def_node = maybe_def.getNode();
if (def_node != null && def_node.getElementType() == PyTokenTypes.DEF_KEYWORD) {
@@ -24,7 +24,7 @@ import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterPro
import com.jetbrains.python.psi.PyArgumentList;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyDecorator;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
/**
@@ -37,9 +37,9 @@ public class PyArgumentListFixer extends PyFixer<PyArgumentList> {
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyArgumentList arguments) throws IncorrectOperationException {
final PsiElement rBrace = PyUtil.getChildByFilter(arguments, PyTokenTypes.CLOSE_BRACES, 0);
final PsiElement rBrace = PyPsiUtils.getChildByFilter(arguments, PyTokenTypes.CLOSE_BRACES, 0);
if (arguments.getParent() instanceof PyClass || arguments.getParent() instanceof PyDecorator) {
final PsiElement lBrace = PyUtil.getChildByFilter(arguments, PyTokenTypes.OPEN_BRACES, 0);
final PsiElement lBrace = PyPsiUtils.getChildByFilter(arguments, PyTokenTypes.OPEN_BRACES, 0);
if (lBrace != null && rBrace == null) {
final Document document = editor.getDocument();
document.insertString(arguments.getTextRange().getEndOffset(), ")");
@@ -23,7 +23,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyArgumentList;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.psi.PyUtil.sure;
@@ -40,7 +40,7 @@ public class PyClassFixer extends PyFixer<PyClass> {
}
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyClass pyClass) throws IncorrectOperationException {
final PsiElement colon = PyUtil.getFirstChildOfType(pyClass, PyTokenTypes.COLON);
final PsiElement colon = PyPsiUtils.getFirstChildOfType(pyClass, PyTokenTypes.COLON);
if (colon == null) {
final PyArgumentList argList = PsiTreeUtil.getChildOfType(pyClass, PyArgumentList.class);
final int colonOffset = sure(argList).getTextRange().getEndOffset();
@@ -24,7 +24,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyConditionalStatementPart;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.psi.PyUtil.sure;
@@ -45,18 +45,18 @@ public class PyConditionalStatementPartFixer extends PyFixer<PyConditionalStatem
throws IncorrectOperationException {
final PyExpression condition = statementPart.getCondition();
final Document document = editor.getDocument();
final PsiElement colon = PyUtil.getFirstChildOfType(statementPart, PyTokenTypes.COLON);
final PsiElement colon = PyPsiUtils.getFirstChildOfType(statementPart, PyTokenTypes.COLON);
if (colon == null) {
if (condition != null) {
final PsiElement firstNonComment = PyUtil.getFirstNonCommentAfter(condition.getNextSibling());
final PsiElement firstNonComment = PyPsiUtils.getFirstNonCommentAfter(condition.getNextSibling());
if (firstNonComment != null && !":".equals(firstNonComment.getNode().getText())) {
document.insertString(firstNonComment.getTextRange().getEndOffset(), ":");
}
}
else {
final TokenSet keywords = TokenSet.create(PyTokenTypes.IF_KEYWORD, PyTokenTypes.ELIF_KEYWORD, PyTokenTypes.WHILE_KEYWORD);
final PsiElement keywordToken = PyUtil.getChildByFilter(statementPart,
keywords, 0);
final PsiElement keywordToken = PyPsiUtils.getChildByFilter(statementPart,
keywords, 0);
final int offset = sure(keywordToken).getTextRange().getEndOffset();
document.insertString(offset, " :");
processor.registerUnresolvedError(offset + 1);
@@ -22,7 +22,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyExceptPart;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.psi.PyUtil.sure;
@@ -40,9 +40,9 @@ public class PyExceptFixer extends PyFixer<PyExceptPart> {
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyExceptPart exceptPart) throws IncorrectOperationException {
final PsiElement colon = PyUtil.getFirstChildOfType(exceptPart, PyTokenTypes.COLON);
final PsiElement colon = PyPsiUtils.getFirstChildOfType(exceptPart, PyTokenTypes.COLON);
if (colon == null) {
final PsiElement exceptToken = PyUtil.getFirstChildOfType(exceptPart, PyTokenTypes.EXCEPT_KEYWORD);
final PsiElement exceptToken = PyPsiUtils.getFirstChildOfType(exceptPart, PyTokenTypes.EXCEPT_KEYWORD);
int offset = sure(exceptToken).getTextRange().getEndOffset();
final PyExpression exceptClass = exceptPart.getExceptClass();
if (exceptClass != null) {
@@ -21,7 +21,7 @@ import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyForPart;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.psi.PyUtil.sure;
@@ -39,16 +39,16 @@ public class PyForPartFixer extends PyFixer<PyForPart> {
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyForPart forPart) {
final PsiElement colon = PyUtil.getFirstChildOfType(forPart, PyTokenTypes.COLON);
final PsiElement colon = PyPsiUtils.getFirstChildOfType(forPart, PyTokenTypes.COLON);
final Document document = editor.getDocument();
final PsiElement forToken = PyUtil.getFirstChildOfType(forPart, PyTokenTypes.FOR_KEYWORD);
final PsiElement forToken = PyPsiUtils.getFirstChildOfType(forPart, PyTokenTypes.FOR_KEYWORD);
if (colon == null) {
String textToInsert = ":";
PsiElement sourceOrTarget = forPart.getSource();
PsiElement positionToInsert = sourceOrTarget;
if (sourceOrTarget == null) {
sourceOrTarget = forPart.getTarget();
final PsiElement inToken = PyUtil.getFirstChildOfType(forPart, PyTokenTypes.IN_KEYWORD);
final PsiElement inToken = PyPsiUtils.getFirstChildOfType(forPart, PyTokenTypes.IN_KEYWORD);
if (inToken == null) {
if (sourceOrTarget == null) {
positionToInsert = sure(forToken);
@@ -22,7 +22,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyParameterList;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
/**
@@ -39,7 +39,7 @@ public class PyFunctionFixer extends PyFixer<PyFunction> {
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyFunction function)
throws IncorrectOperationException {
final PsiElement colon = PyUtil.getFirstChildOfType(function, PyTokenTypes.COLON);
final PsiElement colon = PyPsiUtils.getFirstChildOfType(function, PyTokenTypes.COLON);
if (!isFakeFunction(function) && colon == null) {
final PyParameterList parameterList = function.getParameterList();
if (function.getNameNode() == null) {
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
/**
@@ -37,7 +38,7 @@ public class PyMissingBracesFixer extends PyFixer<PyElement> {
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyElement psiElement)
throws IncorrectOperationException {
if (psiElement instanceof PySetLiteralExpression || psiElement instanceof PyDictLiteralExpression) {
final PsiElement lastChild = PyUtil.getFirstNonCommentBefore(psiElement.getLastChild());
final PsiElement lastChild = PyPsiUtils.getFirstNonCommentBefore(psiElement.getLastChild());
if (lastChild != null && !"}".equals(lastChild.getText())) {
editor.getDocument().insertString(lastChild.getTextRange().getEndOffset(), "}");
}
@@ -45,7 +46,7 @@ public class PyMissingBracesFixer extends PyFixer<PyElement> {
else if (psiElement instanceof PyListLiteralExpression ||
psiElement instanceof PySliceExpression ||
psiElement instanceof PySubscriptionExpression) {
final PsiElement lastChild = PyUtil.getFirstNonCommentBefore(psiElement.getLastChild());
final PsiElement lastChild = PyPsiUtils.getFirstNonCommentBefore(psiElement.getLastChild());
if (lastChild != null && !"]".equals(lastChild.getText())) {
editor.getDocument().insertString(lastChild.getTextRange().getEndOffset(), "]");
}
@@ -23,7 +23,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyParameterList;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.psi.PyUtil.as;
@@ -42,8 +42,8 @@ public class PyParameterListFixer extends PyFixer<PyParameterList> {
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyParameterList parameters)
throws IncorrectOperationException {
final PsiElement lBrace = PyUtil.getChildByFilter(parameters, PyTokenTypes.OPEN_BRACES, 0);
final PsiElement rBrace = PyUtil.getChildByFilter(parameters, PyTokenTypes.CLOSE_BRACES, 0);
final PsiElement lBrace = PyPsiUtils.getChildByFilter(parameters, PyTokenTypes.OPEN_BRACES, 0);
final PsiElement rBrace = PyPsiUtils.getChildByFilter(parameters, PyTokenTypes.CLOSE_BRACES, 0);
final PyFunction pyFunction = as(parameters.getParent(), PyFunction.class);
if (pyFunction != null && !PyFunctionFixer.isFakeFunction(pyFunction) && (lBrace == null || rBrace == null)) {
final Document document = editor.getDocument();
@@ -22,6 +22,7 @@ import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.psi.PyUtil.sure;
@@ -41,10 +42,10 @@ public class PyUnconditionalStatementPartFixer extends PyFixer<PyElement> {
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyElement psiElement)
throws IncorrectOperationException {
if (PyUtil.instanceOf(psiElement, PyElsePart.class, PyTryPart.class, PyFinallyPart.class)) {
final PsiElement colon = PyUtil.getFirstChildOfType(psiElement, PyTokenTypes.COLON);
final PsiElement colon = PyPsiUtils.getFirstChildOfType(psiElement, PyTokenTypes.COLON);
if (colon == null) {
final TokenSet keywords = TokenSet.create(PyTokenTypes.ELSE_KEYWORD, PyTokenTypes.TRY_KEYWORD, PyTokenTypes.FINALLY_KEYWORD);
final PsiElement keywordToken = PyUtil.getChildByFilter(psiElement, keywords, 0);
final PsiElement keywordToken = PyPsiUtils.getChildByFilter(psiElement, keywords, 0);
editor.getDocument().insertString(sure(keywordToken).getTextRange().getEndOffset(), ":");
}
}
@@ -23,9 +23,9 @@ import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.PyWithItem;
import com.jetbrains.python.psi.PyWithStatement;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
/**
@@ -38,8 +38,8 @@ public class PyWithFixer extends PyFixer<PyWithStatement> {
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyWithStatement withStatement) throws IncorrectOperationException {
final PsiElement colonToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.COLON);
final PsiElement withToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD);
final PsiElement colonToken = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.COLON);
final PsiElement withToken = PyPsiUtils.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD);
final Document document = editor.getDocument();
if (colonToken == null && withToken != null) {
int insertAt = withToken.getTextRange().getEndOffset();
@@ -52,7 +52,7 @@ public class PyWithFixer extends PyFixer<PyWithStatement> {
else {
final PyExpression expression = lastItem.getExpression();
insertAt = expression.getTextRange().getEndOffset();
final PsiElement asToken = PyUtil.getFirstChildOfType(lastItem, PyTokenTypes.AS_KEYWORD);
final PsiElement asToken = PyPsiUtils.getFirstChildOfType(lastItem, PyTokenTypes.AS_KEYWORD);
if (asToken != null) {
insertAt = asToken.getTextRange().getEndOffset();
final PyExpression target = lastItem.getTarget();
@@ -26,6 +26,7 @@ import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
/**
@@ -54,11 +55,11 @@ public class PySplitIfIntention extends BaseIntentionAction {
final IElementType elementType = elementAtOffset.getNode().getElementType();
if (elementType == PyTokenTypes.COLON) {
elementAtOffset = elementAtOffset.getPrevSibling();
elementAtOffset = PyUtil.getFirstNonCommentBefore(elementAtOffset);
elementAtOffset = PyPsiUtils.getFirstNonCommentBefore(elementAtOffset);
}
else if (elementType == PyTokenTypes.IF_KEYWORD) {
elementAtOffset = elementAtOffset.getNextSibling();
elementAtOffset = PyUtil.getFirstNonCommentAfter(elementAtOffset);
elementAtOffset = PyPsiUtils.getFirstNonCommentAfter(elementAtOffset);
}
PsiElement element = PsiTreeUtil.getParentOfType(elementAtOffset, PyBinaryExpression.class, false);
@@ -87,11 +88,11 @@ public class PySplitIfIntention extends BaseIntentionAction {
final IElementType elementType = elementAtOffset.getNode().getElementType();
if (elementType == PyTokenTypes.COLON) {
elementAtOffset = elementAtOffset.getPrevSibling();
elementAtOffset = PyUtil.getFirstNonCommentBefore(elementAtOffset);
elementAtOffset = PyPsiUtils.getFirstNonCommentBefore(elementAtOffset);
}
else if (elementType == PyTokenTypes.IF_KEYWORD) {
elementAtOffset = elementAtOffset.getNextSibling();
elementAtOffset = PyUtil.getFirstNonCommentAfter(elementAtOffset);
elementAtOffset = PyPsiUtils.getFirstNonCommentAfter(elementAtOffset);
}
PyBinaryExpression element = PsiTreeUtil.getParentOfType(elementAtOffset, PyBinaryExpression.class, false);
@@ -64,8 +64,8 @@ public class DocStringUtil {
@Nullable
public static PyStringLiteralExpression findDocStringExpression(@Nullable PyElement parent) {
if (parent != null) {
PsiElement seeker = PyUtil.getFirstNonCommentAfter(parent.getFirstChild());
if (seeker instanceof PyExpressionStatement) seeker = PyUtil.getFirstNonCommentAfter(seeker.getFirstChild());
PsiElement seeker = PyPsiUtils.getFirstNonCommentAfter(parent.getFirstChild());
if (seeker instanceof PyExpressionStatement) seeker = PyPsiUtils.getFirstNonCommentAfter(seeker.getFirstChild());
if (seeker instanceof PyStringLiteralExpression) return (PyStringLiteralExpression)seeker;
}
return null;
@@ -51,7 +51,6 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.ui.awt.RelativePoint;
@@ -100,44 +99,6 @@ public class PyUtil {
private PyUtil() {
}
public static ASTNode getNextNonWhitespace(ASTNode after) {
ASTNode node = after;
do {
node = node.getTreeNext();
}
while (isWhitespace(node));
return node;
}
public static ASTNode getPreviousNonWhitespace(ASTNode after) {
ASTNode node = after;
do {
node = node.getTreePrev();
}
while (isWhitespace(node));
return node;
}
private static boolean isWhitespace(ASTNode node) {
return node != null && node.getElementType().equals(TokenType.WHITE_SPACE);
}
@Nullable
public static PsiElement getFirstNonCommentAfter(PsiElement start) {
PsiElement seeker = start;
while (seeker instanceof PsiWhiteSpace || seeker instanceof PsiComment) seeker = seeker.getNextSibling();
return seeker;
}
@Nullable
public static PsiElement getFirstNonCommentBefore(PsiElement start) {
PsiElement seeker = start;
while (seeker instanceof PsiWhiteSpace || seeker instanceof PsiComment) {
seeker = seeker.getPrevSibling();
}
return seeker;
}
@NotNull
public static <T extends PyElement> T[] getAllChildrenOfType(@NotNull PsiElement element, @NotNull Class<T> aClass) {
List<T> result = new SmartList<T>();
@@ -917,38 +878,6 @@ public class PyUtil {
}
}
/**
* Returns child element in the psi tree
*
* @param filter Types of expected child
* @param number number
* @param element tree parent node
* @return PsiElement - child psiElement
*/
@Nullable
public static PsiElement getChildByFilter(@NotNull final PsiElement element, final @NotNull TokenSet filter, final int number) {
final ASTNode node = element.getNode();
if (node != null) {
final ASTNode[] children = node.getChildren(filter);
return (0 <= number && number < children.length) ? children[number].getPsi() : null;
}
return null;
}
/**
* Returns first child psi element with specified element type or {@code null} if no such element exists.
* Semantically it's the same as {@code getChildByFilter(element, TokenSet.create(type), 0)}.
*
* @param element tree parent node
* @param type element type expected
* @return child element described
*/
@Nullable
public static PsiElement getFirstChildOfType(@NotNull final PsiElement element, @NotNull PyElementType type) {
final ASTNode child = element.getNode().findChildByType(type);
return child != null ? child.getPsi() : null;
}
/**
* If argument is a PsiDirectory, turn it into a PsiFile that points to __init__.py in that directory.
* If there's no __init__.py there, null is returned, there's no point to resolve to a dir which is not a package.
@@ -157,7 +157,7 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList
}
}
else {
ASTNode before = PyUtil.getNextNonWhitespace(pars[0]);
ASTNode before = PyPsiUtils.getNextNonWhitespaceSibling(pars[0]);
ASTNode anchorBefore;
if (before != null && elementPrecedesElementsOfType(before, PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens())) {
ASTNode comma = createComma();
@@ -265,7 +265,7 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList
break;
}
else if (type == PyTokenTypes.COMMA) {
ASTNode next = PyUtil.getNextNonWhitespace(node);
ASTNode next = PyPsiUtils.getNextNonWhitespaceSibling(node);
if (next == null) {
addArgumentLastWithoutComma(argument);
}
@@ -19,11 +19,10 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.psi.PyUtil;
import org.jetbrains.annotations.NotNull;
import com.jetbrains.python.psi.PyAugAssignmentStatement;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
@@ -55,6 +54,6 @@ public class PyAugAssignmentStatementImpl extends PyElementImpl implements PyAug
@Nullable
public PsiElement getOperation() {
return PyUtil.getChildByFilter(this, PyTokenTypes.AUG_ASSIGN_OPERATIONS, 0);
return PyPsiUtils.getChildByFilter(this, PyTokenTypes.AUG_ASSIGN_OPERATIONS, 0);
}
}
@@ -223,7 +223,7 @@ public class PyElementGeneratorImpl extends PyElementGenerator {
exprNode.addChild(add);
}
else {
ASTNode next = PyUtil.getNextNonWhitespace(closingTokens[closingTokens.length - 1]);
ASTNode next = PyPsiUtils.getNextNonWhitespaceSibling(closingTokens[closingTokens.length - 1]);
if (next != null) {
ASTNode comma = createComma();
exprNode.addChild(comma, next);
@@ -75,7 +75,7 @@ public class PyParameterListImpl extends PyBaseElementImpl<PyParameterListStub>
}
}
}
final ASTNode previous = PyUtil.getPreviousNonWhitespace(beforeWhat);
final ASTNode previous = PyPsiUtils.getPrevNonWhitespaceSibling(beforeWhat);
PyUtil.addListNode(this, param, beforeWhat, !isLast || params.length == 0 ||
previous.getElementType() == PyTokenTypes.COMMA, isLast,
beforeWhat.getElementType() != PyTokenTypes.RPAR);