From 80f7a67f21078bad5bfe7cb23e965b0bf62a9d66 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 11 Sep 2009 15:32:01 +0400 Subject: [PATCH] IDEADEV-40304 --- .../psi/impl/source/parsing/ParseUtil.java | 6 +- .../intellij/slicer/SliceLeafAnalyzer.java | 112 +++++++++++++----- .../src/com/intellij/slicer/SliceNode.java | 57 +++++++-- .../com/intellij/slicer/SliceRootNode.java | 5 +- .../com/intellij/slicer/SliceTreeBuilder.java | 29 +++-- .../PsiRecursiveElementWalkingVisitor.java | 4 - .../src/com/intellij/psi/PsiWalkingState.java | 82 +++++-------- .../src/com/intellij/psi/WalkingState.java | 85 +++++++++++++ .../codeInsight/unwrap/UnwrapHandler.java | 15 +-- .../psi/impl/GeneratedMarkerVisitor.java | 4 +- .../source/PostprocessReformattingAspect.java | 10 +- .../intellij/psi/impl/source/PsiFileImpl.java | 4 +- .../RecursiveTreeElementWalkingVisitor.java | 86 +++++++------- .../psi/impl/source/tree/TreeUtil.java | 40 +++---- .../tree/injected/MultiHostRegistrarImpl.java | 13 +- 15 files changed, 354 insertions(+), 198 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/psi/WalkingState.java diff --git a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ParseUtil.java b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ParseUtil.java index cda0485af058..6072eaeb9f29 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/parsing/ParseUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/parsing/ParseUtil.java @@ -88,16 +88,16 @@ public class ParseUtil { final List comments = new SmartList(); ((TreeElement)root).acceptTree(new RecursiveTreeElementWalkingVisitor(false) { @Override - protected boolean visitNode(TreeElement child) { + protected void visitNode(TreeElement child) { IElementType type = child.getElementType(); if (type == JavaDocElementType.DOC_COMMENT || type == JavaTokenType.END_OF_LINE_COMMENT || type == JavaTokenType.C_STYLE_COMMENT) { comments.add(child); } - if (TreeUtil.isLeafOrCollapsedChameleon(child)) return false; + if (TreeUtil.isLeafOrCollapsedChameleon(child)) return; - return true; + super.visitNode(child); } }); diff --git a/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java b/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java index ad206a815083..c1e1766dcc7b 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java +++ b/java/java-impl/src/com/intellij/slicer/SliceLeafAnalyzer.java @@ -2,14 +2,13 @@ package com.intellij.slicer; import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiJavaReference; import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.WalkingState; import com.intellij.psi.impl.source.tree.SourceUtil; import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; @@ -41,36 +40,93 @@ public class SliceLeafAnalyzer { } }; - @NotNull - public static Collection calcLeafExpressions(@NotNull SliceNode root, @NotNull ProgressIndicator progress) { - root.update(null); - root.getLeafExpressions().clear(); - Collection leaves; - SliceNode duplicate = root.getDuplicate(); - if (duplicate != null) { - leaves = duplicate.getLeafExpressions(); - //null means other - //leaves = ContainerUtil.singleton(PsiUtilBase.NULL_PSI_ELEMENT, LEAF_ELEMENT_EQUALITY); - //return leaves;//todo + private static class SliceNodeGuide implements WalkingState.TreeGuide { + public SliceNode getNextSibling(SliceNode element) { + return element.getNext(); } - else { - SliceUsage sliceUsage = root.getValue(); - Collection children = root.getChildrenUnderProgress(progress); - if (children.isEmpty()) { - PsiElement element = sliceUsage.getElement(); - leaves = ContainerUtil.singleton(element, LEAF_ELEMENT_EQUALITY); - } - else { - leaves = new THashSet(LEAF_ELEMENT_EQUALITY); - for (AbstractTreeNode child : children) { - Collection elements = calcLeafExpressions((SliceNode)child, progress); - leaves.addAll(elements); + public SliceNode getPrevSibling(SliceNode element) { + return element.getPrev(); + } + + public SliceNode getFirstChild(SliceNode element) { + Object[] children = element.getTreeBuilder().getTreeStructure().getChildElements(element); + return children.length == 0 ? null : (SliceNode)children[0]; + } + + public SliceNode getParent(SliceNode element) { + AbstractTreeNode parent = element.getParent(); + return parent instanceof SliceNode ? (SliceNode)parent : null; + } + private static final SliceNodeGuide instance = new SliceNodeGuide(); + } + + @NotNull + public static Collection calcLeafExpressions(@NotNull final SliceNode root) { + WalkingState walkingState = new WalkingState(SliceNodeGuide.instance) { + @Override + public void visit(SliceNode element) { + element.update(null); + element.getLeafExpressions().clear(); + SliceNode duplicate = element.getDuplicate(); + if (duplicate != null) { + element.addLeafExpressions(duplicate.getLeafExpressions()); + } + else { + SliceUsage sliceUsage = element.getValue(); + + Object[] children = element.getTreeBuilder().getTreeStructure().getChildElements(element); + if (children.length == 0) { + PsiElement value = sliceUsage.getElement(); + element.addLeafExpressions(ContainerUtil.singleton(value, LEAF_ELEMENT_EQUALITY)); + } + super.visit(element); } } - } - root.addLeafExpressions(leaves); - return leaves; + @Override + public void elementFinished(SliceNode element) { + SliceNode parent = SliceNodeGuide.instance.getParent(element); + if (parent != null) { + parent.addLeafExpressions(element.getLeafExpressions()); + } + } + }; + walkingState.elementStarted(root); + + return root.getLeafExpressions(); } + + //@NotNull + //public static Collection calcLeafExpressionsSOE(@NotNull SliceNode root, @NotNull ProgressIndicator progress) { + // root.update(null); + // root.getLeafExpressions().clear(); + // Collection leaves; + // SliceNode duplicate = root.getDuplicate(); + // if (duplicate != null) { + // leaves = duplicate.getLeafExpressions(); + // //null means other + // //leaves = ContainerUtil.singleton(PsiUtilBase.NULL_PSI_ELEMENT, LEAF_ELEMENT_EQUALITY); + // //return leaves;//todo + // } + // else { + // SliceUsage sliceUsage = root.getValue(); + // + // Collection children = root.getChildrenUnderProgress(progress); + // if (children.isEmpty()) { + // PsiElement element = sliceUsage.getElement(); + // leaves = ContainerUtil.singleton(element, LEAF_ELEMENT_EQUALITY); + // } + // else { + // leaves = new THashSet(LEAF_ELEMENT_EQUALITY); + // for (AbstractTreeNode child : children) { + // Collection elements = calcLeafExpressions((SliceNode)child); + // leaves.addAll(elements); + // } + // } + // } + // + // root.addLeafExpressions(leaves); + // return leaves; + //} } diff --git a/java/java-impl/src/com/intellij/slicer/SliceNode.java b/java/java-impl/src/com/intellij/slicer/SliceNode.java index 281608bbc8d0..91476bd0a52a 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceNode.java @@ -4,6 +4,7 @@ import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; @@ -32,6 +33,7 @@ public class SliceNode extends AbstractTreeNode implements Duplicate private final SliceTreeBuilder myTreeBuilder; private final Collection leafExpressions = new THashSet(SliceLeafAnalyzer.LEAF_ELEMENT_EQUALITY); protected boolean changed; + private int index; // my index in parent's mycachedchildren protected SliceNode(@NotNull Project project, SliceUsage sliceUsage, @NotNull DuplicateMap targetEqualUsages, @NotNull Collection leafExpressions) { @@ -60,20 +62,44 @@ public class SliceNode extends AbstractTreeNode implements Duplicate @NotNull public Collection getChildren() { + ProgressIndicator current = ProgressManager.getInstance().getProgressIndicator(); + ProgressIndicator indicator = current == null ? new ProgressIndicatorBase() : current; + if (current == null) { + indicator.start(); + } final Collection[] nodes = new Collection[1]; - ProgressManager.getInstance().runProcess(new Runnable(){ + ((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(new Runnable(){ public void run() { nodes[0] = getChildrenUnderProgress(ProgressManager.getInstance().getProgressIndicator()); } - }, new ProgressIndicatorBase()); + }, indicator); + if (current == null) { + indicator.stop(); + } return nodes[0]; } - public Collection getChildrenUnderProgress(ProgressIndicator progress) { - if (myCachedChildren != null || !isValid() || getTreeBuilder().splitByLeafExpressions) { - return myCachedChildren == null ? Collections.emptyList() : myCachedChildren; + SliceNode getNext() { + AbstractTreeNode parent = getParent(); + if (parent instanceof SliceNode) { + Object[] children = getTreeBuilder().getTreeStructure().getChildElements(parent); + return index == children.length - 1 ? null : (SliceNode)children[index + 1]; } - final List children = Collections.synchronizedList(new ArrayList()); + return null; + } + + SliceNode getPrev() { + AbstractTreeNode parent = getParent(); + if (parent instanceof SliceNode) { + Object[] children = getTreeBuilder().getTreeStructure().getChildElements(parent); + return index == 0 ? null : (SliceNode)children[index - 1]; + } + return null; + } + + protected List getChildrenUnderProgress(ProgressIndicator progress) { + if (isUpToDate()) return myCachedChildren == null ? Collections.emptyList() : myCachedChildren; + final List children = new ArrayList(); final SliceManager manager = SliceManager.getInstance(getProject()); manager.runInterruptibly(new Runnable() { public void run() { @@ -81,7 +107,10 @@ public class SliceNode extends AbstractTreeNode implements Duplicate public boolean process(SliceUsage sliceUsage) { manager.checkCanceled(); SliceNode node = new SliceNode(myProject, sliceUsage, targetEqualUsages, getTreeBuilder(), getLeafExpressions()); - children.add(node); + synchronized (children) { + node.index = children.size(); + children.add(node); + } return true; } }; @@ -102,8 +131,18 @@ public class SliceNode extends AbstractTreeNode implements Duplicate }); } }, progress); - myCachedChildren = children; - return myCachedChildren; + + synchronized (children) { + myCachedChildren = children; + } + return children; + } + + private boolean isUpToDate() { + if (myCachedChildren != null || !isValid() || getTreeBuilder().splitByLeafExpressions) { + return true; + } + return false; } @NotNull diff --git a/java/java-impl/src/com/intellij/slicer/SliceRootNode.java b/java/java-impl/src/com/intellij/slicer/SliceRootNode.java index 235cfe534d97..8ff99cd614a1 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceRootNode.java +++ b/java/java-impl/src/com/intellij/slicer/SliceRootNode.java @@ -12,6 +12,7 @@ import javax.swing.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * @author cdr @@ -39,8 +40,8 @@ public abstract class SliceRootNode extends SliceNode { } @Override - public Collection getChildrenUnderProgress(ProgressIndicator progress) { - return getChildren(); + public List getChildrenUnderProgress(ProgressIndicator progress) { + return (List)getChildren(); } @Override diff --git a/java/java-impl/src/com/intellij/slicer/SliceTreeBuilder.java b/java/java-impl/src/com/intellij/slicer/SliceTreeBuilder.java index c016c56a6262..97b88b631478 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceTreeBuilder.java +++ b/java/java-impl/src/com/intellij/slicer/SliceTreeBuilder.java @@ -1,8 +1,8 @@ package com.intellij.slicer; import com.intellij.ide.util.treeView.AbstractTreeBuilder; -import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.ide.util.treeView.AlphaComparator; +import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -10,6 +10,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultTreeModel; @@ -62,16 +63,9 @@ public class SliceTreeBuilder extends AbstractTreeBuilder { public void switchToSplittedNodes() { final SliceRootNode root = (SliceRootNode)getRootNode().getUserObject(); - final Ref> leafExpressions = Ref.create(null); - boolean b = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { - public void run() { - Collection l = SliceLeafAnalyzer.calcLeafExpressions(root, ProgressManager.getInstance().getProgressIndicator()); - leafExpressions.set(l); - } - }, "Expanding all nodes... (may very well take the whole day)", true, root.getProject()); - if (!b) return; + Collection leaves = calcLeafExpressions(root); + if (leaves == null) return; //cancelled - Collection leaves = leafExpressions.get(); if (leaves.isEmpty()) { Messages.showErrorDialog("Unable to find leaf expressions to group by", "Cannot group"); return; @@ -87,6 +81,21 @@ public class SliceTreeBuilder extends AbstractTreeBuilder { getUpdater().addSubtreeToUpdateByElement(root); } + @Nullable("null means canceled") + public static Collection calcLeafExpressions(final SliceRootNode root) { + final Ref> leafExpressions = Ref.create(null); + boolean b = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + public void run() { + Collection l = SliceLeafAnalyzer.calcLeafExpressions(root); + leafExpressions.set(l); + } + }, "Expanding all nodes... (may very well take the whole day)", true, root.getProject()); + if (!b) return null; + + Collection leaves = leafExpressions.get(); + return leaves; + } + public void switchToUnsplittedNodes() { SliceRootNode root = (SliceRootNode)getRootNode().getUserObject(); SliceLeafValueRootNode valueNode = (SliceLeafValueRootNode)root.myCachedChildren.get(0); diff --git a/platform/lang-api/src/com/intellij/psi/PsiRecursiveElementWalkingVisitor.java b/platform/lang-api/src/com/intellij/psi/PsiRecursiveElementWalkingVisitor.java index f4a802fa78ca..54e6db50a2a8 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiRecursiveElementWalkingVisitor.java +++ b/platform/lang-api/src/com/intellij/psi/PsiRecursiveElementWalkingVisitor.java @@ -62,8 +62,4 @@ public abstract class PsiRecursiveElementWalkingVisitor extends PsiElementVisito super.visitFile(file); } - - public void stopWalking() { - myWalkingState.stopWalking(); - } } diff --git a/platform/lang-api/src/com/intellij/psi/PsiWalkingState.java b/platform/lang-api/src/com/intellij/psi/PsiWalkingState.java index 862441433622..db52530eacb0 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiWalkingState.java +++ b/platform/lang-api/src/com/intellij/psi/PsiWalkingState.java @@ -5,69 +5,47 @@ import com.intellij.openapi.diagnostic.Logger; /** * @author cdr */ -public abstract class PsiWalkingState { +public abstract class PsiWalkingState extends WalkingState { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiWalkingState"); - private boolean isDown; - private boolean startedWalking; private final PsiElementVisitor myVisitor; - private boolean stopped; - public abstract void elementFinished(PsiElement element); + private static class PsiTreeGuide implements TreeGuide { + public PsiElement getNextSibling(PsiElement element) { + return element.getNextSibling(); + } + + public PsiElement getPrevSibling(PsiElement element) { + return element.getPrevSibling(); + } + + public PsiElement getFirstChild(PsiElement element) { + return element.getFirstChild(); + } + + public PsiElement getParent(PsiElement element) { + return element.getParent(); + } + + private static final PsiTreeGuide instance = new PsiTreeGuide(); + } protected PsiWalkingState(PsiElementVisitor delegate) { + super(PsiTreeGuide.instance); myVisitor = delegate; } - public void elementStarted(PsiElement element){ - isDown = true; - if (!startedWalking) { - if (element instanceof PsiCompiledElement) { - // do not walk inside compiled PSI since getNextSibling() is too slow there - LOG.error(element+"; Do not use walking visitor inside compiled PSI since getNextSibling() is too slow there"); - } - stopped = false; - startedWalking = true; - walkChildren(element); - startedWalking = false; - } + @Override + public void visit(PsiElement element) { + element.accept(myVisitor); } - private void walkChildren(PsiElement root) { - for (PsiElement element = next(root,root,isDown); element != null && !stopped; element = next(element, root, isDown)) { - isDown = false; // if client visitor did not call default visitElement it means skip subtree - PsiElement parent = element.getParent(); - PsiElement next = element.getNextSibling(); - element.accept(myVisitor); - assert element.getNextSibling() == next; - assert element.getParent() == parent; + @Override + public void elementStarted(PsiElement element) { + if (!startedWalking && element instanceof PsiCompiledElement) { + // do not walk inside compiled PSI since getNextSibling() is too slow there + LOG.error(element+"; Do not use walking visitor inside compiled PSI since getNextSibling() is too slow there"); } - } - private PsiElement next(PsiElement element, PsiElement root, boolean isDown) { - if (isDown) { - PsiElement child = element.getFirstChild(); - if (child != null) return child; - } - // up - while (element != root) { - PsiElement next = element.getNextSibling(); - - elementFinished(element); - if (next != null) { - assert next.getPrevSibling() == element : "Element: "+element+"; next.prev: "+next.getPrevSibling()+"; File: "+element.getContainingFile(); - return next; - } - element = element.getParent(); - } - elementFinished(element); - return null; - } - - public void startedWalking() { - startedWalking = true; - } - - public void stopWalking() { - stopped = true; + super.elementStarted(element); } } diff --git a/platform/lang-api/src/com/intellij/psi/WalkingState.java b/platform/lang-api/src/com/intellij/psi/WalkingState.java new file mode 100644 index 000000000000..833812eee7b3 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/WalkingState.java @@ -0,0 +1,85 @@ +package com.intellij.psi; + +/** + * @author cdr + */ +public abstract class WalkingState { + public interface TreeGuide { + T getNextSibling(T element); + T getPrevSibling(T element); + T getFirstChild(T element); + T getParent(T element); + } + private boolean isDown; + protected boolean startedWalking; + private final TreeGuide myWalker; + private boolean stopped; + + public abstract void elementFinished(T element); + + protected WalkingState(TreeGuide delegate) { + myWalker = delegate; + } + + public void visit(T element) { + elementStarted(element); + } + + public void elementStarted(T element){ + isDown = true; + if (!startedWalking) { + stopped = false; + startedWalking = true; + walkChildren(element); + startedWalking = false; + } + } + + private void walkChildren(T root) { + for (T element = next(root,root,isDown); element != null && !stopped; element = next(element, root, isDown)) { + isDown = false; // if client visitor did not call default visitElement it means skip subtree + T parent = myWalker.getParent(element); + T next = myWalker.getNextSibling(element); + visit(element); + assert myWalker.getNextSibling(element) == next; + assert myWalker.getParent(element) == parent; + } + } + + private T next(T element, T root, boolean isDown) { + if (isDown) { + T child = myWalker.getFirstChild(element); + if (child != null) return child; + } + // up + while (element != root && element!=null) { + T next = myWalker.getNextSibling(element); + + elementFinished(element); + if (next != null) { + Object nextPrev = myWalker.getPrevSibling(next); + if (nextPrev != element) { + String msg = "Element: " + element + "; next.prev: " + nextPrev; + while (true) { + T top = myWalker.getParent(element); + if (top == null) break; + element = top; + } + assert false : msg+" Top:"+element; + } + return next; + } + element = myWalker.getParent(element); + } + elementFinished(element); + return null; + } + + public void startedWalking() { + startedWalking = true; + } + + public void stopWalking() { + stopped = true; + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/unwrap/UnwrapHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/unwrap/UnwrapHandler.java index 4806f6029de2..7c997b2758be 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/unwrap/UnwrapHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/unwrap/UnwrapHandler.java @@ -179,16 +179,17 @@ public class UnwrapHandler implements CodeInsightActionHandler { private void restoreCaretPosition(final PsiFile file) { ((TreeElement)file.getNode()).acceptTree(new RecursiveTreeElementWalkingVisitor() { - protected boolean visitNode(TreeElement element) { + protected void visitNode(TreeElement element) { PsiElement el = element.getPsi(); Integer offset = el.getCopyableUserData(CARET_POS_KEY); - if (offset == null) return true; // continue; - - myEditor.getCaretModel().moveToOffset(el.getTextOffset() + offset); - el.putCopyableUserData(CARET_POS_KEY, null); - - return false; + // continue; + if (offset != null) { + myEditor.getCaretModel().moveToOffset(el.getTextOffset() + offset); + el.putCopyableUserData(CARET_POS_KEY, null); + return; + } + super.visitNode(element); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/GeneratedMarkerVisitor.java b/platform/lang-impl/src/com/intellij/psi/impl/GeneratedMarkerVisitor.java index 5fd3ed469243..d7c42b24872f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/GeneratedMarkerVisitor.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/GeneratedMarkerVisitor.java @@ -5,8 +5,8 @@ import com.intellij.psi.impl.source.tree.RecursiveTreeElementWalkingVisitor; import com.intellij.psi.impl.source.tree.TreeElement; public class GeneratedMarkerVisitor extends RecursiveTreeElementWalkingVisitor { - protected boolean visitNode(TreeElement element) { + protected void visitNode(TreeElement element) { CodeEditUtil.setNodeGenerated(element, true); - return true; + super.visitNode(element); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java index 7b072956ea08..196f733f0f75 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java @@ -165,12 +165,12 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable case ChangeInfo.CONTENTS_CHANGED: if(!CodeEditUtil.isNodeGenerated(affectedChild)) ((TreeElement)affectedChild).acceptTree(new RecursiveTreeElementWalkingVisitor(){ - protected boolean visitNode(TreeElement element) { + protected void visitNode(TreeElement element) { if(CodeEditUtil.isNodeGenerated(element)){ postponeFormatting(viewProvider, element); - return false; + return; } - return true; + super.visitNode(element); } }); break; @@ -447,13 +447,13 @@ public class PostprocessReformattingAspect implements PomModelAspect, Disposable for (final FileElement fileElement : ((SingleRootFileViewProvider)key).getKnownTreeRoots()) { fileElement.acceptTree( new RecursiveTreeElementWalkingVisitor(){ - protected boolean visitNode(TreeElement element) { + protected void visitNode(TreeElement element) { if(CodeEditUtil.isMarkedToReformatBefore(element)) { CodeEditUtil.markToReformatBefore(element, false); rangesToProcess.put(document.createRangeMarker(element.getStartOffset(), element.getStartOffset()), new ReformatWithHeadingWhitespaceAction()); } - return true; + super.visitNode(element); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index dc1f8ba7ace2..088c672fbb0c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -247,7 +247,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF private void switchFromStubToAST(ASTNode root, final Iterator> stubs) { ((TreeElement)root).acceptTree(new RecursiveTreeElementWalkingVisitor() { @Override - protected boolean visitNode(TreeElement tree) { + protected void visitNode(TreeElement tree) { final IElementType type = tree.getElementType(); if (type instanceof IStubElementType && ((IStubElementType)type).shouldCreateStub(tree)) { @@ -279,7 +279,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF base.setNode(tree); base.setStub(null); } - return true; + super.visitNode(tree); } }); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/RecursiveTreeElementWalkingVisitor.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/RecursiveTreeElementWalkingVisitor.java index ae1b5dd9aeb2..ee58d58f8a57 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/RecursiveTreeElementWalkingVisitor.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/RecursiveTreeElementWalkingVisitor.java @@ -1,62 +1,64 @@ package com.intellij.psi.impl.source.tree; +import com.intellij.lang.ASTNode; +import com.intellij.psi.WalkingState; + public abstract class RecursiveTreeElementWalkingVisitor extends TreeElementVisitor{ - private boolean startedWalking; - private boolean isDown; private final boolean myDoTransform; protected RecursiveTreeElementWalkingVisitor() { this(true); } + protected RecursiveTreeElementWalkingVisitor(boolean doTransform) { myDoTransform = doTransform; } - @Override public void visitLeaf(LeafElement leaf) { + private static class ASTTreeGuide implements WalkingState.TreeGuide { + public ASTNode getNextSibling(ASTNode element) { + return element.getTreeNext(); + } + + public ASTNode getPrevSibling(ASTNode element) { + return element.getTreePrev(); + } + + public ASTNode getFirstChild(ASTNode element) { + return element.getFirstChildNode(); + } + + public ASTNode getParent(ASTNode element) { + return element.getTreeParent(); + } + + private static final ASTTreeGuide instance = new ASTTreeGuide(); + } + + private final WalkingState myWalkingState = new WalkingState(ASTTreeGuide.instance) { + @Override + public void elementFinished(ASTNode element) { + + } + + @Override + public void visit(ASTNode element) { + ((TreeElement)element).acceptTree(RecursiveTreeElementWalkingVisitor.this); + } + }; + + @Override + public void visitLeaf(LeafElement leaf) { visitNode(leaf); } - @Override public void visitComposite(CompositeElement composite) { - isDown = visitNode(composite); - if (!startedWalking) { - startedWalking = true; - if (myDoTransform || !TreeUtil.isCollapsedChameleon(composite)) { - walk(composite); - } - startedWalking = false; - } + @Override + public void visitComposite(CompositeElement composite) { + visitNode(composite); } - private void walk(TreeElement root) { - for (TreeElement element = next(root, root); element != null; element = next(element, root)) { - CompositeElement parent = element.getTreeParent(); - TreeElement next = element.getTreeNext(); - isDown = false; // if client visitor did not call default visitElement it means skip subtree - element.acceptTree(this); - assert element.getTreeNext() == next; - assert element.getTreeParent() == parent; + protected void visitNode(TreeElement element){ + if (myDoTransform || !TreeUtil.isCollapsedChameleon(element)) { + myWalkingState.elementStarted(element); } } - - private TreeElement next(TreeElement element, TreeElement root) { - if (isDown) { - TreeElement child = element.getFirstChildNode(); - if (child != null) return child; - } - - // up - while (element != root) { - TreeElement next = element.getTreeNext(); - if (next != null) { - assert next.getTreePrev() == element : "Element: "+element+"; next.prev: "+next.getTreePrev()+"; File: "+ SharedImplUtil.getContainingFile(element); - return next; - } - element = element.getTreeParent(); - } - return null; - } - - protected boolean visitNode(TreeElement element){ - return true; - } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/TreeUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/TreeUtil.java index df6db8ffc752..daf2172fa6d9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/TreeUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/TreeUtil.java @@ -26,12 +26,9 @@ public class TreeUtil { } } - public static void ensureParsedRecursively(ASTNode node) { - if (node != null) { - for (ASTNode cur = node.getFirstChildNode(); cur != null; cur = cur.getTreeNext()) { - ensureParsedRecursively(cur); - } - } + public static void ensureParsedRecursively(@NotNull ASTNode node) { + ((TreeElement)node).acceptTree(new RecursiveTreeElementWalkingVisitor() { + }); } public static boolean isCollapsedChameleon(ASTNode node) { @@ -102,9 +99,8 @@ public class TreeUtil { } public static boolean isLeafOrCollapsedChameleon(ASTNode node) { - if (node instanceof LeafElement) return true; - if (node instanceof LazyParseableElement && !((LazyParseableElement)node).isParsed()) return true; - return false; + return node instanceof LeafElement || + node instanceof LazyParseableElement && !((LazyParseableElement)node).isParsed(); } @Nullable @@ -112,7 +108,7 @@ public class TreeUtil { if (isLeafOrCollapsedChameleon(element)) { return element; } - else{ + else { for(TreeElement child = element.getFirstChildNode(); child != null; child = child.getTreeNext()){ TreeElement leaf = findFirstLeafOrChameleon(child); if (leaf != null) return leaf; @@ -126,13 +122,11 @@ public class TreeUtil { if (element instanceof LeafElement){ return (LeafElement)element; } - else{ - for(ASTNode child = element.getLastChildNode(); child != null; child = child.getTreePrev()){ - LeafElement leaf = findLastLeaf(child); - if (leaf != null) return leaf; - } - return null; + for(ASTNode child = element.getLastChildNode(); child != null; child = child.getTreePrev()){ + LeafElement leaf = findLastLeaf(child); + if (leaf != null) return leaf; } + return null; } @Nullable @@ -238,22 +232,18 @@ public class TreeUtil { final TreeElement[] result = {null}; element.acceptTree(new RecursiveTreeElementWalkingVisitor(expandChameleons) { @Override - protected boolean visitNode(TreeElement node) { - if (result[0] != null) return false; + protected void visitNode(TreeElement node) { + if (result[0] != null) return; if (commonParent != null) { initStrongWhitespaceHolder(commonParent, node, false); } - if (!expandChameleons && isLeafOrCollapsedChameleon(node)) { + if (!expandChameleons && isCollapsedChameleon(node) || node instanceof LeafElement || node.getElementType() == searchedType) { result[0] = node; - return false; + return; } - if (node instanceof LeafElement || node.getElementType() == searchedType) { - result[0] = node; - return false; - } - return super.visitNode(node); + super.visitNode(node); } }); return result[0]; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java index bc4a1bb3d70d..3cfea4ec70ab 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java @@ -57,12 +57,6 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar { private VirtualFile myHostVirtualFile; private final PsiElement myContextElement; private final PsiFile myHostPsiFile; - private static final TreeElementVisitor CLEAR_CACHES_VISITOR = new RecursiveTreeElementWalkingVisitor(){ - protected boolean visitNode(TreeElement element) { - element.clearCaches(); - return true; - } - }; MultiHostRegistrarImpl(@NotNull Project project, @NotNull PsiFile hostPsiFile, @NotNull PsiElement contextElement) { myProject = project; @@ -320,7 +314,12 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar { String newText = entry.getValue(); leaf.rawReplaceWithText(newText); } - ((TreeElement)parsedNode).acceptTree(CLEAR_CACHES_VISITOR); + ((TreeElement)parsedNode).acceptTree(new RecursiveTreeElementWalkingVisitor(){ + protected void visitNode(TreeElement element) { + element.clearCaches(); + super.visitNode(element); + } + }); } private static PsiFile registerDocument(final DocumentWindowImpl documentWindow,