diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index c0d34d63e4eb..43af151d9762 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -301,7 +301,7 @@ public class CompositeElement extends TreeElement { return false; } - protected int textMatches(CharSequence buffer, int start) { + protected int textMatches(@NotNull CharSequence buffer, int start) { int curOffset = start; for (TreeElement child = getFirstChildNode(); child != null; child = child.getTreeNext()) { curOffset = child.textMatches(buffer, curOffset); @@ -310,6 +310,36 @@ public class CompositeElement extends TreeElement { return curOffset; } + /* + protected int textMatches(final CharSequence buffer, final int start) { + final int[] curOffset = {start}; + acceptTree(new RecursiveTreeElementWalkingVisitor() { + @Override + public void visitLeaf(LeafElement leaf) { + matchText(leaf); + } + + private void matchText(TreeElement leaf) { + curOffset[0] = leaf.textMatches(buffer, curOffset[0]); + if (curOffset[0] == -1) { + stopWalking(); + } + } + + @Override + public void visitComposite(CompositeElement composite) { + if (composite instanceof LazyParseableElement && !((LazyParseableElement)composite).isParsed()) { + matchText(composite); + } + else { + super.visitComposite(composite); + } + } + }); + return curOffset[0]; + } + */ + @Nullable public final PsiElement findChildByRoleAsPsiElement(int role) { ASTNode element = findChildByRole(role); @@ -635,7 +665,7 @@ public class CompositeElement extends TreeElement { public void replaceAllChildrenToChildrenOf(final ASTNode anotherParent) { TreeUtil.ensureParsed(getFirstChildNode()); TreeUtil.ensureParsed(anotherParent.getFirstChildNode()); - final ASTNode firstChild1 = anotherParent.getFirstChildNode(); + final ASTNode firstChild = anotherParent.getFirstChildNode(); ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ public void makeChange(TreeChangeEvent destinationTreeChange) { destinationTreeChange.addElementaryChange(anotherParent, ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, anotherParent)); @@ -643,7 +673,7 @@ public class CompositeElement extends TreeElement { } }, (TreeElement)anotherParent); - if (firstChild1 != null) { + if (firstChild != null) { ChangeUtil.prepareAndRunChangeAction(new ChangeUtil.ChangeAction(){ public void makeChange(TreeChangeEvent destinationTreeChange) { if(getTreeParent() != null){ @@ -651,12 +681,12 @@ public class CompositeElement extends TreeElement { changeInfo.setOldLength(getTextLength()); destinationTreeChange.addElementaryChange(CompositeElement.this, changeInfo); rawRemoveAllChildren(); - rawAddChildren((TreeElement)firstChild1); + rawAddChildren((TreeElement)firstChild); } else{ final TreeElement first = getFirstChildNode(); remove(destinationTreeChange, first, null); - add(destinationTreeChange, CompositeElement.this, (TreeElement)firstChild1); + add(destinationTreeChange, CompositeElement.this, (TreeElement)firstChild); repairRemovedElement(CompositeElement.this, first); } } @@ -702,7 +732,7 @@ public class CompositeElement extends TreeElement { return LeafElement.getPsi(clazz, getPsi(), LOG); } - final PsiElement createAndStorePsi() { + private PsiElement createAndStorePsi() { PsiElement psi = createPsiNoLock(); myWrapper = psi; return psi; @@ -741,7 +771,7 @@ public class CompositeElement extends TreeElement { last.rawInsertAfterMe(first); } - if (DebugUtil.CHECK) DebugUtil.checkTreeStructure(this); + DebugUtil.checkTreeStructure(this); } public void rawRemoveAllChildren() { @@ -751,6 +781,23 @@ public class CompositeElement extends TreeElement { } } + void createAllChildrenPsi() { + synchronized (PsiLock.LOCK) { // guard for race condition with getPsi() + acceptTree(CREATE_CHILDREN_PSI); + } + } + private static final RecursiveTreeElementWalkingVisitor CREATE_CHILDREN_PSI = new RecursiveTreeElementWalkingVisitor(false) { + @Override + public void visitLeaf(LeafElement leaf) { + } + + @Override + public void visitComposite(CompositeElement composite) { + composite.createAndStorePsi(); + super.visitComposite(composite); + } + }; + private static void repairRemovedElement(final CompositeElement oldParent, final TreeElement oldChild) { if(oldChild == null) return; final FileElement treeElement = DummyHolderFactory.createHolder(oldParent.getManager(), null, false).getTreeElement(); @@ -797,7 +844,7 @@ public class CompositeElement extends TreeElement { final TreeElement oldChild, final TreeElement newChild) { oldChild.rawReplaceWithList(newChild); - final ReplaceChangeInfoImpl change = (ReplaceChangeInfoImpl)ChangeInfoImpl.create(ChangeInfo.REPLACE, newChild); + final ReplaceChangeInfoImpl change = new ReplaceChangeInfoImpl(newChild); sourceTreeChange.addElementaryChange(newChild, change); change.setReplaced(oldChild); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java index f7aea664ab12..a87434b60263 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java @@ -27,34 +27,23 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.ILazyParseableElementType; import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class LazyParseableElement extends CompositeElement { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.LazyParseableElement"); - private static final RecursiveTreeElementWalkingVisitor CREATE_PSI = new RecursiveTreeElementWalkingVisitor(false) { - @Override - public void visitLeaf(LeafElement leaf) { - } - - @Override - public void visitComposite(CompositeElement composite) { - composite.createAndStorePsi(); - super.visitComposite(composite); - } - }; - private static class ChameleonLock { private ChameleonLock() {} + @NonNls @Override public String toString() { return "chameleon parsing lock"; } } - private final Object lock = new ChameleonLock(); - + private final ChameleonLock lock = new ChameleonLock(); private CharSequence myText; public LazyParseableElement(@NotNull IElementType type, CharSequence text) { @@ -80,74 +69,68 @@ public class LazyParseableElement extends CompositeElement { @NotNull @Override public String getText() { - synchronized (lock) { - if (myText != null) { - return myText.toString(); - } + CharSequence text = myText(); + if (text != null) { + return text.toString(); } return super.getText(); } + @NotNull public CharSequence getChars() { - synchronized (lock) { - if (myText != null) { - return myText; - } + CharSequence text = myText(); + if (text != null) { + return text; } - return getText(); + return super.getText(); } @Override public int getTextLength() { - synchronized (lock) { - if (myText != null) { - return myText.length(); - } + CharSequence text = myText(); + if (text != null) { + return text.length(); } return super.getTextLength(); } @Override public int getNotCachedLength() { - synchronized (lock) { - if (myText != null) { - return myText.length(); - } + CharSequence text = myText(); + if (text != null) { + return text.length(); } return super.getNotCachedLength(); } @Override public int hc() { - synchronized (lock) { - if (myText != null) { - return LeafElement.leafHC(myText); - } - else { - return super.hc(); - } - } + CharSequence text = myText(); + return text == null ? super.hc() : LeafElement.leafHC(text); } @Override - protected int textMatches(CharSequence buffer, int start) { - synchronized (lock) { - if (myText != null) { - return LeafElement.leafTextMatches(myText, buffer, start); - } + protected int textMatches(@NotNull CharSequence buffer, int start) { + CharSequence text = myText(); + if (text != null) { + return LeafElement.leafTextMatches(text, buffer, start); } return super.textMatches(buffer, start); } public boolean isParsed() { + return myText() == null; + } + + private CharSequence myText() { synchronized (lock) { - return myText == null; + return myText; } } @Override public void setFirstChildNode(TreeElement child) { - if (myText != null) { + if (myText() != null) { LOG.error("Mutating collapsed chameleon"); } super.setFirstChildNode(child); @@ -155,7 +138,7 @@ public class LazyParseableElement extends CompositeElement { @Override public void setLastChildNode(TreeElement child) { - if (myText != null) { + if (myText() != null) { LOG.error("Mutating collapsed chameleon"); } super.setLastChildNode(child); @@ -199,14 +182,16 @@ public class LazyParseableElement extends CompositeElement { //} //ensure PSI is created all at once, to reduce contention of PsiLock in CompositeElement.getPsi() - ((TreeElement)parsedNode).acceptTree(CREATE_PSI); + if (parsedNode instanceof CompositeElement) { + ((CompositeElement)parsedNode).createAllChildrenPsi(); + } parsedNode.getTreeNext(); } } @Override public void rawAddChildren(@NotNull TreeElement first) { - if (myText != null) { + if (myText() != null) { LOG.error("Mutating collapsed chameleon"); } super.rawAddChildren(first); @@ -229,13 +214,12 @@ public class LazyParseableElement extends CompositeElement { } public int copyTo(char[] buffer, int start) { - synchronized (lock) { - if (myText == null) return -1; - - if (buffer != null) { - CharArrayUtil.getChars(myText, buffer, start); - } - return start + myText.length(); + CharSequence text = myText(); + if (text == null) return -1; + + if (buffer != null) { + CharArrayUtil.getChars(text, buffer, start); } + return start + text.length(); } }