From bd9022596d8c2c42847d16dd9a2aa3a13b88a96d Mon Sep 17 00:00:00 2001 From: John Camelon Date: Tue, 15 Mar 2005 00:39:42 +0000 Subject: [PATCH] Patch for Devin Steffler. This patch includes: - several enhancements made to the DOM AST View to improve performance - "Display Problems" button that will display all found IASTProblems in the AST via the Search View --- .../cdt/core/parser/util/ArrayUtil.java | 26 ++ .../DOMAST/CPPPopulateASTViewAction.java | 45 ++- .../tests/DOMAST/CPopulateASTViewAction.java | 44 ++- .../eclipse/cdt/ui/tests/DOMAST/DOMAST.java | 49 ++- .../eclipse/cdt/ui/tests/DOMAST/DOMQuery.java | 31 +- .../ui/tests/DOMAST/FindIASTNameTarget.java | 4 +- .../cdt/ui/tests/DOMAST/TreeParent.java | 285 +++++++++++------- 7 files changed, 318 insertions(+), 166 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java index 34c62ceee4b..9191b863dc3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java @@ -188,4 +188,30 @@ public class ArrayUtil { if( array[i] == obj ) return true; return false; } + + /** + * Removes all of the nulls from the array and returns a new + * array that contains all of the non-null elements. + * + * If there are no nulls in the original array then the original + * array is returned. + * + * @return + */ + public static Object[] removeNulls(Class c, Object[] array) { + if( array == null ) + return (Object[]) Array.newInstance( c, 0 ); + + int i = 0; + int j = 0; + Object[] newArray = new Object[array.length]; + for( ; i < array.length; i++ ){ + if( array[i] != null ) newArray[j++] = array[i]; + } + + if (j 0 && + // TODO Devin !(node instanceof ICPPASTLinkageSpecification) below is a hack job for bug 86993 + if (!(node instanceof ICPPASTLinkageSpecification) && !(nodeLocations.length > 0 && nodeLocations[0].getNodeOffset() >= 0 && nodeLocations[0].getNodeLength() > 0)) return PROCESS_CONTINUE; @@ -89,8 +94,14 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate parent.addChild(tree); // set filter flags - if (node instanceof IASTProblemHolder || node instanceof IASTProblem) + if (node instanceof IASTProblemHolder || node instanceof IASTProblem) { tree.setFiltersFlag(TreeObject.FLAG_PROBLEM); + + if (node instanceof IASTProblemHolder) + astProblems = (IASTProblem[])ArrayUtil.append(IASTProblemHolder.class, astProblems, ((IASTProblemHolder)node).getProblem()); + else + astProblems = (IASTProblem[])ArrayUtil.append(IASTProblemHolder.class, astProblems, node); + } if (node instanceof IASTPreprocessorStatement) tree.setFiltersFlag(TreeObject.FLAG_PREPROCESSOR); if (node instanceof IASTPreprocessorIncludeStatement) @@ -247,20 +258,18 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate int index = 0; for(int i=0; i includes.length) { - IASTPreprocessorIncludeStatement[] newIncludes = new IASTPreprocessorIncludeStatement[includes.length * 2]; - for (int j=0; j=0; i--) { + outerLoop: for (int i=treeIncludes.length-1; i>=0; i--) { if (treeIncludes[i] == null) continue; - for(int j=root.getChildren().length-1; j>=0; j--) { + for(int j=root.getChildren(false).length-1; j>=0; j--) { if (monitor != null && monitor.isCanceled()) return; - child = root.getChildren()[j]; - - if (treeIncludes[i] != child && + child = root.getChildren(false)[j]; + + if (child != null && treeIncludes[i] != child && includes[i] instanceof ASTInclusionStatement && ((ASTNode)child.getNode()).getOffset() >= ((ASTInclusionStatement)includes[i]).startOffset && ((ASTNode)child.getNode()).getOffset() <= ((ASTInclusionStatement)includes[i]).endOffset) { @@ -286,4 +295,8 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate } } } + + public IASTProblem[] getASTProblems() { + return astProblems; + } } diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/CPopulateASTViewAction.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/CPopulateASTViewAction.java index 694a39185e6..ccf12bea9dd 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/CPopulateASTViewAction.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/CPopulateASTViewAction.java @@ -33,6 +33,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.c.CASTVisitor; import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator; +import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.parser.scanner2.LocationMap.ASTInclusionStatement; import org.eclipse.core.runtime.IProgressMonitor; @@ -41,6 +42,7 @@ import org.eclipse.core.runtime.IProgressMonitor; * @author dsteffle */ public class CPopulateASTViewAction extends CASTVisitor implements IPopulateDOMASTAction { + private static final int INITIAL_PROBLEM_SIZE = 4; private static final int INITIAL_INCLUDE_STATEMENT_SIZE = 8; { shouldVisitNames = true; @@ -58,6 +60,7 @@ public class CPopulateASTViewAction extends CASTVisitor implements IPopulateDOMA TreeParent root = null; IProgressMonitor monitor = null; + IASTProblem[] astProblems = new IASTProblem[INITIAL_PROBLEM_SIZE]; public CPopulateASTViewAction(IASTTranslationUnit tu, IProgressMonitor monitor) { root = new TreeParent(tu); @@ -83,13 +86,21 @@ public class CPopulateASTViewAction extends CASTVisitor implements IPopulateDOMA parent.addChild(tree); // set filter flags - if (node instanceof IASTProblemHolder || node instanceof IASTProblem) + if (node instanceof IASTProblemHolder || node instanceof IASTProblem) { tree.setFiltersFlag(TreeObject.FLAG_PROBLEM); + + if (node instanceof IASTProblemHolder) + astProblems = (IASTProblem[])ArrayUtil.append(IASTProblemHolder.class, astProblems, ((IASTProblemHolder)node).getProblem()); + else + astProblems = (IASTProblem[])ArrayUtil.append(IASTProblemHolder.class, astProblems, node); + } if (node instanceof IASTPreprocessorStatement) tree.setFiltersFlag(TreeObject.FLAG_PREPROCESSOR); if (node instanceof IASTPreprocessorIncludeStatement) tree.setFiltersFlag(TreeObject.FLAG_INCLUDE_STATEMENTS); + + return PROCESS_CONTINUE; } @@ -220,20 +231,18 @@ public class CPopulateASTViewAction extends CASTVisitor implements IPopulateDOMA int index = 0; for(int i=0; i includes.length) { - IASTPreprocessorIncludeStatement[] newIncludes = new IASTPreprocessorIncludeStatement[includes.length * 2]; - for (int j=0; j=0; i--) { + outerLoop: for (int i=treeIncludes.length-1; i>=0; i--) { if (treeIncludes[i] == null) continue; - for(int j=root.getChildren().length-1; j>=0; j--) { + for(int j=root.getChildren(false).length-1; j>=0; j--) { if (monitor != null && monitor.isCanceled()) return; - child = root.getChildren()[j]; - - if (treeIncludes[i] != child && + child = root.getChildren(false)[j]; + + if (child != null && + treeIncludes[i] != child && includes[i] instanceof ASTInclusionStatement && ((ASTNode)child.getNode()).getOffset() >= ((ASTInclusionStatement)includes[i]).startOffset && ((ASTNode)child.getNode()).getOffset() <= ((ASTInclusionStatement)includes[i]).endOffset) { @@ -259,4 +269,8 @@ public class CPopulateASTViewAction extends CASTVisitor implements IPopulateDOMA } } } + + public IASTProblem[] getASTProblems() { + return astProblems; + } } diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMAST.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMAST.java index 734267709c6..39406e0d1c3 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMAST.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMAST.java @@ -131,10 +131,12 @@ public class DOMAST extends ViewPart { private static final String POPUPMENU = "#PopupMenu"; //$NON-NLS-1$ private static final String OPEN_DECLARATIONS = "Open Declarations"; //$NON-NLS-1$ private static final String OPEN_REFERENCES = "Open References"; //$NON-NLS-1$ + private static final String DISPLAY_PROBLEMS = "Display Problems"; //$NON-NLS-1$ TreeViewer viewer; private DrillDownAdapter drillDownAdapter; private Action openDeclarationsAction; private Action openReferencesAction; + private Action displayProblemsAction; private Action displayNodeTypeAction; private Action displayNodeSignatureAction; private Action displayExpressionAction; @@ -164,9 +166,10 @@ public class DOMAST extends ViewPart { public class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider { private static final String POPULATING_AST_VIEW = "Populating AST View"; //$NON-NLS-1$ - private TreeParent invisibleRoot; + private TreeParent invisibleRoot; private TreeParent tuTreeParent = null; private IASTTranslationUnit tu = null; + private IASTProblem[] astProblems = null; public ViewContentProvider() { } @@ -343,7 +346,7 @@ public class DOMAST extends ViewPart { return Status.CANCEL_STATUS; if (monitor.isCanceled()) return Status.CANCEL_STATUS; - monitor.beginTask(name, 7); + monitor.beginTask(name, 8); start=System.currentTimeMillis(); IPopulateDOMASTAction action = null; @@ -414,6 +417,12 @@ public class DOMAST extends ViewPart { System.out.println("[DOM AST View] done " + GROUPING_AST + ": " + (System.currentTimeMillis()- start) ); root.addChild(action.getTree()); + + // get the IASTProblems from the action + if (action instanceof CPopulateASTViewAction) + astProblems = ((CPopulateASTViewAction)action).getASTProblems(); + else if (action instanceof CPPPopulateASTViewAction) + astProblems = ((CPPPopulateASTViewAction)action).getASTProblems(); provider.setInvisibleRoot(root); @@ -423,11 +432,15 @@ public class DOMAST extends ViewPart { return Status.OK_STATUS; } - + } + + public IASTProblem[] getASTProblems() { + return astProblems; + } private void initialize() { - invisibleRoot = new TreeParent(null); // blank the AST View, when the job above is complete it will update the AST View with the proper tree + invisibleRoot = new TreeParent(); // blank the AST View, when the job above is complete it will update the AST View with the proper tree } protected void setInvisibleRoot(TreeParent root) { @@ -533,6 +546,7 @@ public class DOMAST extends ViewPart { class ViewLabelProvider extends LabelProvider { public String getText(Object obj) { + if (obj == null) return ""; return obj.toString(); } @@ -598,6 +612,7 @@ public class DOMAST extends ViewPart { } class NameSorter extends ViewerSorter { + } public DOMAST() { @@ -628,6 +643,7 @@ public class DOMAST extends ViewPart { viewer.setLabelProvider(new ViewLabelProvider()); viewer.setInput(getViewSite()); + makeActions(); hookContextMenu(); hookSingleClickAction(); @@ -757,6 +773,7 @@ public class DOMAST extends ViewPart { manager.add(clearAction); manager.add(new Separator()); manager.add(searchNamesAction); + manager.add(displayProblemsAction); manager.add(new Separator()); drillDownAdapter.addNavigationActions(manager); } @@ -840,6 +857,10 @@ public class DOMAST extends ViewPart { openReferencesAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages() .getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); + displayProblemsAction = new DisplayProblemsResultAction(); + displayProblemsAction.setText(DISPLAY_PROBLEMS); + displayProblemsAction.setImageDescriptor(DOMASTPluginImages.DESC_IASTProblem); + displayNodeTypeAction = new Action() { public void run() { ISelection selection = viewer.getSelection(); @@ -1026,6 +1047,26 @@ public class DOMAST extends ViewPart { NewSearchUI.runQuery(job); } } + + private class DisplayProblemsResultAction extends Action { + private static final String IASTPROBLEM = "IASTProblem"; //$NON-NLS-1$ + private static final String PROBLEMS_FOUND = "Problems Found"; //$NON-NLS-1$ + protected void displayProblems(IASTProblem[] problems, String queryLabel, String pattern) { + DOMQuery job = new DOMQuery(problems, queryLabel, pattern); + NewSearchUI.activateSearchResultView(); + NewSearchUI.runQuery(job); + } + + public void run() { + if (viewer.getTree().getItems().length == 0) { + showMessage(DOM_AST_HAS_NO_CONTENT); + } + + if (viewer.getContentProvider() instanceof ViewContentProvider) { + displayProblems(((ViewContentProvider)viewer.getContentProvider()).getASTProblems(), PROBLEMS_FOUND, IASTPROBLEM); + } + } + } private void hookSingleClickAction() { viewer.addSelectionChangedListener(new ISelectionChangedListener() { diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMQuery.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMQuery.java index ac4a3857fa3..604afb7377f 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMQuery.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/DOMQuery.java @@ -12,7 +12,9 @@ package org.eclipse.cdt.ui.tests.DOMAST; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.search.BasicSearchMatch; import org.eclipse.cdt.core.search.IMatch; @@ -41,15 +43,15 @@ public class DOMQuery extends CSearchQuery implements ISearchQuery { private static final String BLANK_STRING = ""; //$NON-NLS-1$ private CSearchResult _result; - private IASTName[] names = null; + private IASTNode[] nodes = null; private String queryLabel = null; /** * */ - public DOMQuery(IASTName[] names, String queryLabel, String pattern) { + public DOMQuery(IASTNode[] nodes, String queryLabel, String pattern) { super(CTestPlugin.getWorkspace(), pattern, false, null, null, null, queryLabel, null); - this.names = names; + this.nodes = nodes; this.queryLabel = queryLabel; } @@ -66,15 +68,15 @@ public class DOMQuery extends CSearchQuery implements ISearchQuery { collector.aboutToStart(); - for (int i=0; i 0 && location[0] instanceof IASTFileLocation ) fileName = ((IASTFileLocation)location[0]).getFileName(); // TODO Devin this is in two places now, put into one, and fix up the location[0] for things like macros else @@ -83,11 +85,11 @@ public class DOMQuery extends CSearchQuery implements ISearchQuery { path = new Path(fileName); file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path); - if (names[i].getNodeLocations().length > 0) { // fix for 84223 - start = names[i].getNodeLocations()[0].getNodeOffset(); - end = names[i].getNodeLocations()[0].getNodeOffset() + names[i].getNodeLocations()[0].getNodeLength(); + if (nodes[i].getNodeLocations().length > 0) { // fix for 84223 + start = nodes[i].getNodeLocations()[0].getNodeOffset(); + end = nodes[i].getNodeLocations()[0].getNodeOffset() + nodes[i].getNodeLocations()[0].getNodeLength(); - collector.acceptMatch( createMatch(file, start, end, names[i], path ) ); + collector.acceptMatch( createMatch(file, start, end, nodes[i], path ) ); } } } catch (CoreException ce) {} @@ -99,7 +101,7 @@ public class DOMQuery extends CSearchQuery implements ISearchQuery { return new Status(IStatus.OK, CTestPlugin.getPluginId(), 0, BLANK_STRING, null); //$NON-NLS-1$ } - public IMatch createMatch( Object fileResource, int start, int end, IASTName name, IPath referringElement ) { + public IMatch createMatch( Object fileResource, int start, int end, IASTNode node, IPath referringElement ) { BasicSearchMatch result = new BasicSearchMatch(); if( fileResource instanceof IResource ) result.resource = (IResource) fileResource; @@ -111,7 +113,12 @@ public class DOMQuery extends CSearchQuery implements ISearchQuery { result.parentName = BLANK_STRING; //$NON-NLS-1$ result.referringElement = referringElement; - result.name = name.toString(); + if (node instanceof IASTName) + result.name = node.toString(); + else if (node instanceof IASTProblem) + result.name = ((IASTProblem)node).getMessage(); + else + result.name = node.toString(); result.type = ICElement.C_FIELD; // TODO Devin static for now, want something like BasicSearchResultCollector#setElementInfo result.visibility = ICElement.CPP_PUBLIC; // TODO Devin static for now, want something like BasicSearchResultCollector#setElementInfo diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/FindIASTNameTarget.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/FindIASTNameTarget.java index 333fae18574..7b56d5aa92a 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/FindIASTNameTarget.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/FindIASTNameTarget.java @@ -401,7 +401,7 @@ public class FindIASTNameTarget implements IFindReplaceTarget, IFindReplaceTarge // get the TreeObject from the AST View's model corresponding to that name TreeObject treeNode = null; TreeItem treeItem = null; - treeNode = tuTreeParent.findTreeObject(foundName, true, true); + treeNode = tuTreeParent.findTreeObject(foundName, true); if (treeNode != null && treeNode.getParent() != null) { // found a matching TreeObject, so expand the tree to that object @@ -413,7 +413,7 @@ public class FindIASTNameTarget implements IFindReplaceTarget, IFindReplaceTarge ((searchForward && index < matchingNames.length) || (!searchForward && index >= 0))) { foundName = findNextMatchingName( findString, searchForward, caseSensitive, wholeWord, regExSearch ); - treeNode = tuTreeParent.findTreeObject(foundName, true, true); + treeNode = tuTreeParent.findTreeObject(foundName, true); if (treeNode != null && treeNode.getParent() != null) { // found a matching TreeObject, so expand the tree to that object diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/TreeParent.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/TreeParent.java index 90f494d75d8..693799bf476 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/TreeParent.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/DOMAST/TreeParent.java @@ -10,81 +10,103 @@ **********************************************************************/ package org.eclipse.cdt.ui.tests.DOMAST; -import java.util.ArrayList; -import java.util.Iterator; +import java.util.Arrays; +import java.util.Comparator; -import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; /** * @author dsteffle */ public class TreeParent extends TreeObject { - private ArrayList children; + private static final TreeObject[] EMPTY_CHILDREN_ARRAY = new TreeObject[0]; + private static final int DEFAULT_NODE_CHAIN_SIZE = 4; + private static final int DEFAULT_CHILDREN_SIZE = 4; + int index=0; + private TreeObject[] children; + boolean cleanupedElements = false; + + public int getStartSearch() { + return index; + } + public TreeParent() { + super(null); + children = EMPTY_CHILDREN_ARRAY; + } + public TreeParent(IASTNode node) { super(node); - children = new ArrayList(); + children = new TreeObject[DEFAULT_CHILDREN_SIZE]; } public void addChild(TreeObject child) { - int index = 0; - for(int i=0; i0; - } - - /** - * Returns the TreeParent whose IASTNode is the parent of the IASTNode. - * - * @param trees - * @param node - * @return - */ - private TreeParent findTreeParentForNode(TreeObject[] trees, IASTNode node) { - for (int i=0; i0; + } + /** * Returns the TreeParent whose IASTNode is the parent of the IASTNode. * @@ -94,15 +116,43 @@ public class TreeParent extends TreeObject { public TreeParent findTreeParentForNode(IASTNode node) { if (node == null || node.getParent() == null) return null; - Iterator itr = children.iterator(); - while (itr.hasNext()) { - Object o = itr.next(); - if (o != null && o instanceof TreeParent) { - if ( ((TreeParent)o).getNode() == node.getParent() ) { - return (TreeParent)o; - } else if ( ((TreeParent)o).hasChildren() ){ - TreeParent tree = findTreeParentForNode( ((TreeParent)o).getChildren(), node ); - if (tree != null) return tree; + IASTNode parentToFind = node.getParent(); + + // first check this node before checking children + if (this.getNode() == parentToFind) { + return this; + } + + // build the chain of nodes... and use it to search the tree for the TreeParent that owns the node's parent + IASTNode[] nodeChain = new IASTNode[DEFAULT_NODE_CHAIN_SIZE]; + IASTNode topNode = node.getParent(); + ArrayUtil.append(IASTNode.class, nodeChain, node); + nodeChain = (IASTNode[])ArrayUtil.append(IASTNode.class, nodeChain, topNode); + while(topNode.getParent() != null && !(topNode.getParent() instanceof IASTTranslationUnit)) { + topNode = topNode.getParent(); + nodeChain = (IASTNode[])ArrayUtil.append(IASTNode.class, nodeChain, topNode); + } + + // loop through the chain of nodes and use it to only search the necessary children required to find the node + TreeObject[] childrenToSearch = children; + int j=getStartSearch(); + outerLoop: for(int i=nodeChain.length-1; i>=0; i--) { + if (nodeChain[i] != null) { + parentToFind = nodeChain[i]; + + for(; j>=0; j--) { // use the TreeParent's index to start searching at the end of it's children (performance optimization) + if (j=0; i--) { + if (nodeChain[i] != null) { + nodeToFind = nodeChain[i]; - if (equalNodes(node, ((TreeParent)o).getNode(), useOffset, useName)) - return (TreeParent)o; - - // search the children - if ( ((TreeParent)o).hasChildren() ){ - TreeParent tree = findTreeObject( ((TreeParent)o).getChildren(), node, useOffset, useName ); - if (tree != null) return tree; + for(int j=0; j