mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEADEV-40304
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+44
-42
@@ -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];
|
||||
|
||||
+6
-7
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user