IDEADEV-40304

This commit is contained in:
Alexey Kudravtsev
2009-09-11 15:32:01 +04:00
parent fa757619fe
commit 80f7a67f21
15 changed files with 354 additions and 198 deletions
@@ -88,16 +88,16 @@ public class ParseUtil {
final List<ASTNode> comments = new SmartList<ASTNode>();
((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);
}
});
@@ -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<PsiElement> calcLeafExpressions(@NotNull SliceNode root, @NotNull ProgressIndicator progress) {
root.update(null);
root.getLeafExpressions().clear();
Collection<PsiElement> 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<SliceNode> {
public SliceNode getNextSibling(SliceNode element) {
return element.getNext();
}
else {
SliceUsage sliceUsage = root.getValue();
Collection<? extends AbstractTreeNode> children = root.getChildrenUnderProgress(progress);
if (children.isEmpty()) {
PsiElement element = sliceUsage.getElement();
leaves = ContainerUtil.singleton(element, LEAF_ELEMENT_EQUALITY);
}
else {
leaves = new THashSet<PsiElement>(LEAF_ELEMENT_EQUALITY);
for (AbstractTreeNode child : children) {
Collection<PsiElement> 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<PsiElement> calcLeafExpressions(@NotNull final SliceNode root) {
WalkingState<SliceNode> walkingState = new WalkingState<SliceNode>(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<PsiElement> calcLeafExpressionsSOE(@NotNull SliceNode root, @NotNull ProgressIndicator progress) {
// root.update(null);
// root.getLeafExpressions().clear();
// Collection<PsiElement> 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<? extends AbstractTreeNode> children = root.getChildrenUnderProgress(progress);
// if (children.isEmpty()) {
// PsiElement element = sliceUsage.getElement();
// leaves = ContainerUtil.singleton(element, LEAF_ELEMENT_EQUALITY);
// }
// else {
// leaves = new THashSet<PsiElement>(LEAF_ELEMENT_EQUALITY);
// for (AbstractTreeNode child : children) {
// Collection<PsiElement> elements = calcLeafExpressions((SliceNode)child);
// leaves.addAll(elements);
// }
// }
// }
//
// root.addLeafExpressions(leaves);
// return leaves;
//}
}
@@ -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<SliceUsage> implements Duplicate
private final SliceTreeBuilder myTreeBuilder;
private final Collection<PsiElement> leafExpressions = new THashSet<PsiElement>(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<PsiElement> leafExpressions) {
@@ -60,20 +62,44 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> implements Duplicate
@NotNull
public Collection<? extends AbstractTreeNode> 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<? extends AbstractTreeNode> getChildrenUnderProgress(ProgressIndicator progress) {
if (myCachedChildren != null || !isValid() || getTreeBuilder().splitByLeafExpressions) {
return myCachedChildren == null ? Collections.<AbstractTreeNode>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<AbstractTreeNode> children = Collections.synchronizedList(new ArrayList<AbstractTreeNode>());
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<? extends AbstractTreeNode> getChildrenUnderProgress(ProgressIndicator progress) {
if (isUpToDate()) return myCachedChildren == null ? Collections.<AbstractTreeNode>emptyList() : myCachedChildren;
final List<AbstractTreeNode> children = new ArrayList<AbstractTreeNode>();
final SliceManager manager = SliceManager.getInstance(getProject());
manager.runInterruptibly(new Runnable() {
public void run() {
@@ -81,7 +107,10 @@ public class SliceNode extends AbstractTreeNode<SliceUsage> 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<SliceUsage> 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
@@ -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<? extends AbstractTreeNode> getChildrenUnderProgress(ProgressIndicator progress) {
return getChildren();
public List<? extends AbstractTreeNode> getChildrenUnderProgress(ProgressIndicator progress) {
return (List<? extends AbstractTreeNode>)getChildren();
}
@Override
@@ -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<Collection<PsiElement>> leafExpressions = Ref.create(null);
boolean b = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
Collection<PsiElement> 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<PsiElement> leaves = calcLeafExpressions(root);
if (leaves == null) return; //cancelled
Collection<PsiElement> 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<PsiElement> calcLeafExpressions(final SliceRootNode root) {
final Ref<Collection<PsiElement>> leafExpressions = Ref.create(null);
boolean b = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
Collection<PsiElement> 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<PsiElement> leaves = leafExpressions.get();
return leaves;
}
public void switchToUnsplittedNodes() {
SliceRootNode root = (SliceRootNode)getRootNode().getUserObject();
SliceLeafValueRootNode valueNode = (SliceLeafValueRootNode)root.myCachedChildren.get(0);
@@ -62,8 +62,4 @@ public abstract class PsiRecursiveElementWalkingVisitor extends PsiElementVisito
super.visitFile(file);
}
public void stopWalking() {
myWalkingState.stopWalking();
}
}
@@ -5,69 +5,47 @@ import com.intellij.openapi.diagnostic.Logger;
/**
* @author cdr
*/
public abstract class PsiWalkingState {
public abstract class PsiWalkingState extends WalkingState<PsiElement> {
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<PsiElement> {
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);
}
}
@@ -0,0 +1,85 @@
package com.intellij.psi;
/**
* @author cdr
*/
public abstract class WalkingState<T> {
public interface TreeGuide<T> {
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<T> myWalker;
private boolean stopped;
public abstract void elementFinished(T element);
protected WalkingState(TreeGuide<T> 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;
}
}
@@ -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);
}
});
}
@@ -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);
}
}
@@ -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);
}
});
}
@@ -247,7 +247,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
private void switchFromStubToAST(ASTNode root, final Iterator<StubElement<?>> 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);
}
});
}
@@ -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<ASTNode> {
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<ASTNode> myWalkingState = new WalkingState<ASTNode>(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;
}
}
@@ -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];
@@ -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,