From c47233a435005b8b09017cc9d372c012a9527eb9 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 1 Jul 2015 13:41:30 +0300 Subject: [PATCH] Move several related methods for navigating PSI and AST trees from PyUtil to PyPsiUtil --- .../jetbrains/python/psi/impl/PyPsiUtils.java | 116 +++++++++++++++++- .../codeInsight/PyMethodNameTypedHandler.java | 3 +- .../fixers/PyArgumentListFixer.java | 6 +- .../smartEnter/fixers/PyClassFixer.java | 4 +- .../PyConditionalStatementPartFixer.java | 10 +- .../smartEnter/fixers/PyExceptFixer.java | 6 +- .../smartEnter/fixers/PyForPartFixer.java | 8 +- .../smartEnter/fixers/PyFunctionFixer.java | 4 +- .../fixers/PyMissingBracesFixer.java | 5 +- .../fixers/PyParameterListFixer.java | 6 +- .../PyUnconditionalStatementPartFixer.java | 5 +- .../smartEnter/fixers/PyWithFixer.java | 8 +- .../intentions/PySplitIfIntention.java | 9 +- .../python/documentation/DocStringUtil.java | 4 +- .../src/com/jetbrains/python/psi/PyUtil.java | 71 ----------- .../python/psi/impl/PyArgumentListImpl.java | 4 +- .../impl/PyAugAssignmentStatementImpl.java | 5 +- .../psi/impl/PyElementGeneratorImpl.java | 2 +- .../python/psi/impl/PyParameterListImpl.java | 2 +- 19 files changed, 159 insertions(+), 119 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java index 3167ffeeff22..b825956e0b7f 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java @@ -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); diff --git a/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java b/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java index d2b01b388544..0d394c21bad3 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java +++ b/python/src/com/jetbrains/python/codeInsight/PyMethodNameTypedHandler.java @@ -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) { diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java index eb6a2ac58af3..8d3e022be183 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java @@ -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 { @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(), ")"); diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java index f75bfef2e671..b49915c23c2f 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java @@ -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 { } 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(); diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java index c2688a8a6358..aa2393ad38be 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java @@ -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 { @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) { diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java index 0e9824855da2..244b55d22c77 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java @@ -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 { @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); diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java index db3694755129..4bfead4c551b 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java @@ -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 { @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) { diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java index 32a7de6a8145..ddfed4b6b923 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java @@ -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 { 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 { 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(), "]"); } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java index e4359a43c640..53dd4fab9c9d 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java @@ -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 { @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(); diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java index 7885ae1e8d15..d01b4d440f16 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java @@ -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 { 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(), ":"); } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java index 1b179d9684a5..618f785b9d17 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java @@ -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 { @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 { 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(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java index 764e352bcf40..4425a8619244 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java @@ -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); diff --git a/python/src/com/jetbrains/python/documentation/DocStringUtil.java b/python/src/com/jetbrains/python/documentation/DocStringUtil.java index e84ca6a0eeae..121e550ee577 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringUtil.java +++ b/python/src/com/jetbrains/python/documentation/DocStringUtil.java @@ -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; diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 331c2d16ab70..a78999c025ac 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -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[] getAllChildrenOfType(@NotNull PsiElement element, @NotNull Class aClass) { List result = new SmartList(); @@ -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. diff --git a/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java b/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java index 5d46f6f60a3c..05763cbcaec2 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyArgumentListImpl.java @@ -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); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyAugAssignmentStatementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyAugAssignmentStatementImpl.java index bcb31b823aea..0237b648a153 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyAugAssignmentStatementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyAugAssignmentStatementImpl.java @@ -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); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java index a1ba0b72a850..b1f36a7874a1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java @@ -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); diff --git a/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java b/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java index f8e6dd24c7e8..0be3713cc9b7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java @@ -75,7 +75,7 @@ public class PyParameterListImpl extends PyBaseElementImpl } } } - 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);