/* * Copyright 2000-2011 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. */ /* * @author max */ package com.intellij.psi.impl.source; import com.intellij.extapi.psi.StubBasedPsiElementBase; import com.intellij.ide.util.PsiNavigationSupport; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.diagnostic.Logger; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.StubBasedPsiElement; import com.intellij.psi.impl.CheckUtil; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.impl.source.tree.ChangeUtil; import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.impl.source.tree.SharedImplUtil; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubElement; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class JavaStubPsiElement<T extends StubElement> extends StubBasedPsiElementBase<T> implements StubBasedPsiElement<T> { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.JavaStubPsiElement"); public JavaStubPsiElement(@NotNull T stub, @NotNull IStubElementType nodeType) { super(stub, nodeType); } public JavaStubPsiElement(@NotNull ASTNode node) { super(node); } @Override @NotNull public Language getLanguage() { return JavaLanguage.INSTANCE; } @Override public PsiElement getParent() { return getParentByStub(); } @Override public int getTextOffset() { return calcTreeElement().getTextOffset(); } protected CompositeElement calcTreeElement() { return (CompositeElement)getNode(); } @Override public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException { CheckUtil.checkWritable(this); TreeElement elementCopy = ChangeUtil.copyToElement(element); calcTreeElement().addInternal(elementCopy, elementCopy, null, null); elementCopy = ChangeUtil.decodeInformation(elementCopy); return SourceTreeToPsiMap.treeElementToPsi(elementCopy); } @Override public PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException { CheckUtil.checkWritable(this); TreeElement elementCopy = ChangeUtil.copyToElement(element); calcTreeElement().addInternal(elementCopy, elementCopy, SourceTreeToPsiMap.psiElementToTree(anchor), Boolean.TRUE); elementCopy = ChangeUtil.decodeInformation(elementCopy); return SourceTreeToPsiMap.treeElementToPsi(elementCopy); } @Override public PsiElement addAfter(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException { CheckUtil.checkWritable(this); TreeElement elementCopy = ChangeUtil.copyToElement(element); calcTreeElement().addInternal(elementCopy, elementCopy, SourceTreeToPsiMap.psiElementToTree(anchor), Boolean.FALSE); elementCopy = ChangeUtil.decodeInformation(elementCopy); return SourceTreeToPsiMap.treeElementToPsi(elementCopy); } @Override public final void checkAdd(@NotNull PsiElement element) throws IncorrectOperationException { CheckUtil.checkWritable(this); } @Override public PsiElement addRange(PsiElement first, PsiElement last) throws IncorrectOperationException { return SharedImplUtil.addRange(this, first, last, null, null); } @Override public PsiElement addRangeBefore(@NotNull PsiElement first, @NotNull PsiElement last, PsiElement anchor) throws IncorrectOperationException { return SharedImplUtil.addRange(this, first, last, SourceTreeToPsiMap.psiElementToTree(anchor), Boolean.TRUE); } @Override public PsiElement addRangeAfter(PsiElement first, PsiElement last, PsiElement anchor) throws IncorrectOperationException { return SharedImplUtil.addRange(this, first, last, SourceTreeToPsiMap.psiElementToTree(anchor), Boolean.FALSE); } @Override public void delete() throws IncorrectOperationException { ASTNode treeElement = calcTreeElement(); LOG.assertTrue(treeElement.getTreeParent() != null); CheckUtil.checkWritable(this); ((CompositeElement)treeElement.getTreeParent()).deleteChildInternal(treeElement); } @Override public void deleteChildRange(PsiElement first, PsiElement last) throws IncorrectOperationException { CheckUtil.checkWritable(this); if (first == null) { LOG.assertTrue(last == null); return; } ASTNode firstElement = SourceTreeToPsiMap.psiElementToTree(first); ASTNode lastElement = SourceTreeToPsiMap.psiElementToTree(last); CompositeElement treeElement = calcTreeElement(); LOG.assertTrue(firstElement.getTreeParent() == treeElement); LOG.assertTrue(lastElement.getTreeParent() == treeElement); CodeEditUtil.removeChildren(treeElement, firstElement, lastElement); } @Override public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException { CompositeElement treeElement = calcTreeElement(); return SharedImplUtil.doReplace(this, treeElement, newElement); } @Override public void navigate(boolean requestFocus) { final Navigatable navigatable = PsiNavigationSupport.getInstance().getDescriptor(this); if (navigatable != null) { navigatable.navigate(requestFocus); } } @Override public boolean canNavigate() { return PsiNavigationSupport.getInstance().canNavigate(this); } @Override public boolean canNavigateToSource() { return canNavigate(); } @Override public void acceptChildren(@NotNull PsiElementVisitor visitor) { SharedImplUtil.acceptChildren(visitor, calcTreeElement()); } @Override protected Object clone() { CompositeElement treeElement = calcTreeElement(); CompositeElement treeElementClone = (CompositeElement)(treeElement.getTreeParent() != null ? treeElement.copyElement() : (ASTNode)treeElement.clone()); /* if (treeElementClone.getPsiElement() != null) { return treeElementClone.getPsiElement(); } */ return cloneImpl(treeElementClone); } protected StubBasedPsiElementBase cloneImpl(@NotNull CompositeElement treeElementClone) { StubBasedPsiElementBase clone = (StubBasedPsiElementBase)super.clone(); clone.setNode(treeElementClone); treeElementClone.setPsi(clone); return clone; } @Override public void subtreeChanged() { final CompositeElement compositeElement = calcTreeElement(); if (compositeElement != null) compositeElement.clearCaches(); super.subtreeChanged(); } @Override @NotNull public PsiElement[] getChildren() { PsiElement psiChild = getFirstChild(); if (psiChild == null) return EMPTY_ARRAY; int count = 0; while (psiChild != null) { count++; psiChild = psiChild.getNextSibling(); } PsiElement[] answer = new PsiElement[count]; count = 0; psiChild = getFirstChild(); while (psiChild != null) { answer[count++] = psiChild; psiChild = psiChild.getNextSibling(); } return answer; } }