diff --git a/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java b/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java index d6baaf6db5bf..345108557404 100644 --- a/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java @@ -68,8 +68,10 @@ import java.util.Map; */ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { private static final Logger LOG = Logger.getInstance("#com.intellij.lang.impl.PsiBuilderImpl"); + // function stored in PsiBuilderImpl' user data which called during reparse when merge algorithm is not sure what to merge - public static final Key, ThreeState>> CUSTOM_COMPARATOR = Key.create("CUSTOM_COMPARATOR"); + public static final Key, ThreeState>> + CUSTOM_COMPARATOR = Key.create("CUSTOM_COMPARATOR"); private final Project myProject; private PsiFile myFile; @@ -283,7 +285,6 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { private ProductionMarker myFirstChild; private ProductionMarker myLastChild; private int myHC = -1; - private LighterASTNode[] myCachedChildren; private StartMarker() { myEdgeTokenBinder = DEFAULT_LEFT_EDGE_TOKEN_BINDER; @@ -298,7 +299,6 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { myFirstChild = myLastChild = null; myHC = -1; myEdgeTokenBinder = DEFAULT_LEFT_EDGE_TOKEN_BINDER; - myCachedChildren = null; } public int hc() { @@ -324,7 +324,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } for (int i = builder.myLexStarts[lexIdx]; i < builder.myLexStarts[myDoneMarker.myLexemeIndex]; i++) { - hc += bufArray != null ? bufArray[i]:buf.charAt(i); + hc += bufArray != null ? bufArray[i] : buf.charAt(i); } myHC = hc; @@ -381,7 +381,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { public void doneBefore(final IElementType type, final Marker before, final String errorMessage) { final StartMarker marker = (StartMarker)before; - myBuilder.myProduction.add(myBuilder.myProduction.lastIndexOf(marker), new ErrorItem(myBuilder, errorMessage, marker.myLexemeIndex)); + myBuilder.myProduction.add(myBuilder.myProduction.lastIndexOf(marker), + new ErrorItem(myBuilder, errorMessage, marker.myLexemeIndex)); doneBefore(type, before); } @@ -436,7 +437,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { public int hc() { if (myHC == -1) { int hc = 0; - if (myTokenType instanceof TokenWrapper){ + if (myTokenType instanceof TokenWrapper) { final String value = ((TokenWrapper)myTokenType).getValue(); for (int i = 0; i < value.length(); i++) { hc += value.charAt(i); @@ -1008,7 +1009,6 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } private void bind(final StartMarker rootMarker, final CompositeElement rootNode) { - final Stack nodes = new Stack(); StartMarker curMarker = rootMarker; CompositeElement curNode = rootNode; @@ -1026,7 +1026,6 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { final CompositeElement childNode = createComposite(marker); curNode.rawAddChildren(childNode); - nodes.push(curNode); curNode = childNode; item = marker.myFirstChild != null ? marker.myFirstChild : marker.myDoneMarker; @@ -1043,7 +1042,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } else if (item instanceof DoneMarker) { curMarker = (StartMarker)((DoneMarker)item).myStart.myParent; - curNode = nodes.pop(); + curNode = curNode.getTreeParent(); item = ((DoneMarker)item).myStart; } @@ -1067,7 +1066,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { return curToken; } - private int collapseLeaves(CompositeElement ast, StartMarker startMarker) { + private int collapseLeaves(final CompositeElement ast, final StartMarker startMarker) { final int start = myLexStarts[startMarker.myLexemeIndex]; final int end = myLexStarts[startMarker.myDoneMarker.myLexemeIndex]; final TreeElement leaf = createLeaf(startMarker.myType, start, end); @@ -1093,7 +1092,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } @Nullable - public static String getErrorMessage(LighterASTNode node) { + public static String getErrorMessage(final LighterASTNode node) { if (node instanceof ErrorItem) return ((ErrorItem)node).myMessage; if (node instanceof StartMarker) { final StartMarker marker = (StartMarker)node; @@ -1229,31 +1228,21 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { myRoot = root; } - @NotNull - public LighterASTNode prepareForGetChildren(@NotNull final LighterASTNode o) { - return o; - } - + @Override @NotNull public LighterASTNode getRoot() { return myRoot; } - public void disposeChildren(final LighterASTNode[] nodes, final int count) { - if (nodes == null) return; - for (int i = 0; i < count; i++) { - final LighterASTNode node = nodes[i]; - if (node instanceof LazyParseableToken) { - myLazyPool.recycle((LazyParseableToken)node); - } - else if (node instanceof Token) { - myPool.recycle((Token)node); - } - } + @Override + @NotNull + public LighterASTNode prepareForGetChildren(@NotNull final LighterASTNode o) { + return o; } private int count; + @Override public int getChildren(@NotNull final LighterASTNode item, @NotNull final Ref into) { if (item instanceof LazyParseableToken) { final FlyweightCapableTreeStructure tree = ((LazyParseableToken)item).parseContents(); @@ -1265,20 +1254,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { StartMarker marker = (StartMarker)item; count = 0; - - if (marker.myCachedChildren != null) { - count = marker.myCachedChildren.length; - if (into.get() == null || into.get().length < count) { - into.set(new LighterASTNode[count]); - } - System.arraycopy(marker.myCachedChildren, 0, into.get(), 0, count); - return count; - } - ProductionMarker child = marker.myFirstChild; - ProductionMarker prevChild = null; int lexIndex = marker.myLexemeIndex; - boolean hasCollapsed = false; while (child != null) { lexIndex = insertLeaves(lexIndex, child.myLexemeIndex, into, marker.myBuilder); @@ -1286,16 +1263,10 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { final int start = marker.myBuilder.myLexStarts[child.myLexemeIndex]; final int end = marker.myBuilder.myLexStarts[((StartMarker)child).myDoneMarker.myLexemeIndex]; insertLeaf(into, start, end, child.getTokenType(), marker.myBuilder); - - if (prevChild != null) prevChild.myNext = child.myNext; - if (marker.myFirstChild == child) marker.myFirstChild = child.myNext; - if (marker.myLastChild == child) marker.myLastChild = prevChild; - hasCollapsed = true; } else { ensureCapacity(into); into.get()[count++] = child; - prevChild = child; } if (child instanceof StartMarker) { @@ -1306,15 +1277,23 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { insertLeaves(lexIndex, marker.myDoneMarker.myLexemeIndex, into, marker.myBuilder); - // kids with collapsed nodes have to be cached - in order for getChildren() to return a same result - if (hasCollapsed) { - marker.myCachedChildren = new LighterASTNode[count]; - System.arraycopy(into.get(), 0, marker.myCachedChildren, 0, count); - } - return count; } + @Override + public void disposeChildren(final LighterASTNode[] nodes, final int count) { + if (nodes == null) return; + for (int i = 0; i < count; i++) { + final LighterASTNode node = nodes[i]; + if (node instanceof LazyParseableToken) { + myLazyPool.recycle((LazyParseableToken)node); + } + else if (node instanceof Token) { + myPool.recycle((Token)node); + } + } + } + private void ensureCapacity(final Ref into) { LighterASTNode[] old = into.get(); if (old == null) { @@ -1379,7 +1358,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { } else { final StartMarker startMarker = (StartMarker)n; - final CompositeElement composite = n == myRoot ? (CompositeElement)myRoot.myBuilder.createRootAST(myRoot) : createComposite(startMarker); + final CompositeElement composite = (n == myRoot) ? (CompositeElement)myRoot.myBuilder.createRootAST(myRoot) + : createComposite(startMarker); startMarker.myBuilder.bind(startMarker, composite); return composite; } @@ -1417,12 +1397,14 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { */ private static class MyList extends ArrayList { private static final Field ourElementDataField; + static { Field f; try { f = ArrayList.class.getDeclaredField("elementData"); f.setAccessible(true); - } catch(NoSuchFieldException e) { + } + catch(NoSuchFieldException e) { // IBM J9 does not have the field f = null; } @@ -1441,8 +1423,9 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder { public int lastIndexOf(final Object o) { if (cachedElementData == null) return super.lastIndexOf(o); - for (int i = size()-1; i >= 0; i--) - if (cachedElementData[i]==o) return i; + for (int i = size() - 1; i >= 0; i--) { + if (cachedElementData[i] == o) return i; + } return -1; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/DebugUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/DebugUtil.java index 15b3a84cb9f6..addc63ded9d9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/DebugUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/DebugUtil.java @@ -19,6 +19,7 @@ package com.intellij.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.lang.LighterASTNode; import com.intellij.lang.LighterASTTokenNode; +import com.intellij.lang.impl.PsiBuilderImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; @@ -153,7 +154,7 @@ public class DebugUtil { StringUtil.repeatSymbol(buffer, ' ', indent); if (tokenType == TokenType.ERROR_ELEMENT) { - buffer.append("PsiErrorElement"); // todo: error message text + buffer.append("PsiErrorElement:").append(PsiBuilderImpl.getErrorMessage(node)); } else if (tokenType == TokenType.WHITE_SPACE) { buffer.append("PsiWhiteSpace"); diff --git a/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java b/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java index 84c9337e0727..c7334ee93512 100644 --- a/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java +++ b/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java @@ -522,11 +522,10 @@ public class PsiBuilderQuickTest { // check light tree composition final FlyweightCapableTreeStructure lightTree = builder.getLightTree(); - final String lightExpected = expected.replaceAll("PsiErrorElement:.*\n", "PsiErrorElement\n"); - assertEquals(lightExpected, DebugUtil.lightTreeToString(lightTree, false)); + assertEquals(expected, DebugUtil.lightTreeToString(lightTree, false)); // verify that light tree can be taken multiple times final FlyweightCapableTreeStructure lightTree2 = builder.getLightTree(); - assertEquals(lightExpected, DebugUtil.lightTreeToString(lightTree2, false)); + assertEquals(expected, DebugUtil.lightTreeToString(lightTree2, false)); // check heavy tree composition final ASTNode root = builder.getTreeBuilt(); diff --git a/platform/util/src/com/intellij/util/diff/FlyweightCapableTreeStructure.java b/platform/util/src/com/intellij/util/diff/FlyweightCapableTreeStructure.java index 1cf1b8f48ff3..3d51c78c2dd6 100644 --- a/platform/util/src/com/intellij/util/diff/FlyweightCapableTreeStructure.java +++ b/platform/util/src/com/intellij/util/diff/FlyweightCapableTreeStructure.java @@ -23,8 +23,13 @@ import org.jetbrains.annotations.NotNull; * @author max */ public interface FlyweightCapableTreeStructure { - @NotNull T prepareForGetChildren(@NotNull T node); - @NotNull T getRoot(); + @NotNull + T getRoot(); + + @NotNull + T prepareForGetChildren(@NotNull T node); + int getChildren(@NotNull T parent, @NotNull Ref into); + void disposeChildren(T[] nodes, int count); }