| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.intellij.psi.impl.source.tree; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.psi.*; |
| import com.intellij.psi.impl.CheckUtil; |
| import com.intellij.psi.impl.source.SourceTreeToPsiMap; |
| import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; |
| import com.intellij.psi.tree.IElementType; |
| import com.intellij.util.CharTable; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| //TODO: rename/regroup? |
| |
| public class SharedImplUtil { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.SharedImplUtil"); |
| |
| private SharedImplUtil() { |
| } |
| |
| public static PsiElement getParent(ASTNode thisElement) { |
| return SourceTreeToPsiMap.treeElementToPsi(thisElement.getTreeParent()); |
| } |
| |
| public static PsiElement getFirstChild(ASTNode element) { |
| return SourceTreeToPsiMap.treeElementToPsi(element.getFirstChildNode()); |
| } |
| |
| @Nullable |
| public static PsiElement getLastChild(ASTNode element) { |
| return SourceTreeToPsiMap.treeElementToPsi(element.getLastChildNode()); |
| } |
| |
| public static PsiElement getNextSibling(ASTNode thisElement) { |
| return SourceTreeToPsiMap.treeElementToPsi(thisElement.getTreeNext()); |
| } |
| |
| public static PsiElement getPrevSibling(ASTNode thisElement) { |
| return SourceTreeToPsiMap.treeElementToPsi(thisElement.getTreePrev()); |
| } |
| |
| public static PsiFile getContainingFile(ASTNode thisElement) { |
| TreeElement element = findFileElement(thisElement); |
| PsiElement psiElement = element == null ? null : element.getPsi(); |
| if (psiElement == null) return null; |
| return psiElement.getContainingFile(); |
| } |
| |
| public static boolean isValid(ASTNode thisElement) { |
| LOG.assertTrue(thisElement instanceof PsiElement); |
| PsiFile file = getContainingFile(thisElement); |
| return file != null && file.isValid(); |
| } |
| |
| public static boolean isWritable(ASTNode thisElement) { |
| PsiFile file = getContainingFile(thisElement); |
| return file == null || file.isWritable(); |
| } |
| |
| public static FileElement findFileElement(@NotNull ASTNode element) { |
| ASTNode parent = element.getTreeParent(); |
| while (parent != null) { |
| element = parent; |
| parent = parent.getTreeParent(); |
| } |
| |
| if (element instanceof FileElement) { |
| return (FileElement)element; |
| } |
| return null; |
| } |
| |
| public static CharTable findCharTableByTree(ASTNode tree) { |
| while (tree != null) { |
| final CharTable userData = tree.getUserData(CharTable.CHAR_TABLE_KEY); |
| if (userData != null) return userData; |
| if (tree instanceof FileElement) return ((FileElement)tree).getCharTable(); |
| tree = tree.getTreeParent(); |
| } |
| LOG.error("Invalid root element"); |
| return null; |
| } |
| |
| public static PsiElement addRange(PsiElement thisElement, |
| PsiElement first, |
| PsiElement last, |
| ASTNode anchor, |
| Boolean before) throws IncorrectOperationException { |
| CheckUtil.checkWritable(thisElement); |
| final CharTable table = findCharTableByTree(SourceTreeToPsiMap.psiElementToTree(thisElement)); |
| |
| TreeElement copyFirst = null; |
| ASTNode copyLast = null; |
| ASTNode next = SourceTreeToPsiMap.psiElementToTree(last).getTreeNext(); |
| ASTNode parent = null; |
| for (ASTNode element = SourceTreeToPsiMap.psiElementToTree(first); element != next; element = element.getTreeNext()) { |
| TreeElement elementCopy = ChangeUtil.copyElement((TreeElement)element, table); |
| if (element == first.getNode()) { |
| copyFirst = elementCopy; |
| } |
| if (element == last.getNode()) { |
| copyLast = elementCopy; |
| } |
| if (parent == null) { |
| parent = elementCopy.getTreeParent(); |
| } |
| else { |
| if(elementCopy.getElementType() == TokenType.WHITE_SPACE) |
| CodeEditUtil.setNodeGenerated(elementCopy, true); |
| parent.addChild(elementCopy, null); |
| } |
| } |
| if (copyFirst == null) return null; |
| copyFirst = ((CompositeElement)SourceTreeToPsiMap.psiElementToTree(thisElement)).addInternal(copyFirst, copyLast, anchor, before); |
| for (TreeElement element = copyFirst; element != null; element = element.getTreeNext()) { |
| element = ChangeUtil.decodeInformation(element); |
| if (element.getTreePrev() == null) { |
| copyFirst = element; |
| } |
| } |
| return SourceTreeToPsiMap.treeElementToPsi(copyFirst); |
| } |
| |
| public static PsiManager getManagerByTree(final ASTNode node) { |
| if(node instanceof FileElement) return node.getPsi().getManager(); |
| return node.getTreeParent().getPsi().getManager(); |
| } |
| |
| public static ASTNode[] getChildrenOfType(ASTNode node, IElementType elementType) { |
| int count = countChildrenOfType(node, elementType); |
| if (count == 0) { |
| return ASTNode.EMPTY_ARRAY; |
| } |
| final ASTNode[] result = new ASTNode[count]; |
| count = 0; |
| for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { |
| if (child.getElementType() == elementType) { |
| result[count++] = child; |
| } |
| } |
| return result; |
| } |
| |
| private static int countChildrenOfType(@NotNull ASTNode node, @NotNull IElementType elementType) { |
| // no lock is needed because all chameleons are expanded already |
| int count = 0; |
| for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { |
| if (child.getElementType() == elementType) { |
| count++; |
| } |
| } |
| |
| return count; |
| } |
| |
| public static void acceptChildren(PsiElementVisitor visitor, CompositeElement root) { |
| TreeElement childNode = root.getFirstChildNode(); |
| |
| while (childNode != null) { |
| final PsiElement psi; |
| if (childNode instanceof PsiElement) { |
| psi = (PsiElement)childNode; |
| } |
| else { |
| psi = childNode.getPsi(); |
| } |
| psi.accept(visitor); |
| |
| childNode = childNode.getTreeNext(); |
| } |
| } |
| |
| public static PsiElement doReplace(PsiElement psiElement, TreeElement treeElement, PsiElement newElement) { |
| CompositeElement treeParent = treeElement.getTreeParent(); |
| LOG.assertTrue(treeParent != null); |
| CheckUtil.checkWritable(psiElement); |
| TreeElement elementCopy = ChangeUtil.copyToElement(newElement); |
| treeParent.replaceChildInternal(treeElement, elementCopy); |
| elementCopy = ChangeUtil.decodeInformation(elementCopy); |
| final PsiElement result = SourceTreeToPsiMap.treeElementToPsi(elementCopy); |
| treeElement.invalidate(); |
| return result; |
| } |
| } |