### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: dom/org/eclipse/jdt/core/dom/ASTVisitor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java,v retrieving revision 1.24 diff -u -r1.24 ASTVisitor.java --- dom/org/eclipse/jdt/core/dom/ASTVisitor.java 27 Jun 2008 16:03:45 -0000 1.24 +++ dom/org/eclipse/jdt/core/dom/ASTVisitor.java 14 Oct 2008 17:58:39 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -143,12 +143,32 @@ *

* * @param node the node to visit + * + * @see #preVisit2(ASTNode) */ public void preVisit(ASTNode node) { // default implementation: do nothing } /** + * Visits the given AST node prior to the type-specific visit. (before visit). + *

+ * The default implementation calls {@link #preVisit(ASTNode)} and then + * returns true. Subclasses may reimplement. + *

+ * + * @param node the node to visit + * @return true if visit(node) should be called, + * and false if the children of this node should be skipped + * @see #preVisit(ASTNode) + * @since 3.5 + */ + public boolean preVisit2(ASTNode node) { + preVisit(node); + return true; + } + + /** * Visits the given AST node following the type-specific visit * (after endVisit). *

Index: dom/org/eclipse/jdt/core/dom/ASTNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java,v retrieving revision 1.77 diff -u -r1.77 ASTNode.java --- dom/org/eclipse/jdt/core/dom/ASTNode.java 27 Jun 2008 16:03:49 -0000 1.77 +++ dom/org/eclipse/jdt/core/dom/ASTNode.java 14 Oct 2008 17:58:39 -0000 @@ -103,7 +103,8 @@ *

*

* ASTs also support the visitor pattern; see the class ASTVisitor - * for details. + * for details. The NodeFinder class can be used to find a specific + * node inside a tree. *

*

* Compilation units created by ASTParser from a @@ -117,6 +118,7 @@ * * @see ASTParser * @see ASTVisitor + * @see NodeFinder * @since 2.0 * @noextend This class is not intended to be subclassed by clients. */ @@ -2473,9 +2475,10 @@ throw new IllegalArgumentException(); } // begin with the generic pre-visit - visitor.preVisit(this); - // dynamic dispatch to internal method for type-specific visit/endVisit - accept0(visitor); + if (visitor.preVisit2(this)) { + // dynamic dispatch to internal method for type-specific visit/endVisit + accept0(visitor); + } // end with the generic post-visit visitor.postVisit(this); } Index: dom/org/eclipse/jdt/core/dom/NodeFinder.java =================================================================== RCS file: dom/org/eclipse/jdt/core/dom/NodeFinder.java diff -N dom/org/eclipse/jdt/core/dom/NodeFinder.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dom/org/eclipse/jdt/core/dom/NodeFinder.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.compiler.IScanner; +import org.eclipse.jdt.core.compiler.ITerminalSymbols; +import org.eclipse.jdt.core.compiler.InvalidInputException; + +/** + * For a given range, finds the covered node and the covering node. + * + * @since 3.5 + */ +public final class NodeFinder { + /** + * This class defines the actual visitor that finds the node. + */ + private static class NodeFinderVisitor extends ASTVisitor { + private int fStart; + private int fEnd; + private ASTNode fCoveringNode; + private ASTNode fCoveredNode; + + NodeFinderVisitor(int offset, int length) { + super(true); // include Javadoc tags + this.fStart= offset; + this.fEnd= offset + length; + } + + public boolean preVisit2(ASTNode node) { + int nodeStart= node.getStartPosition(); + int nodeEnd= nodeStart + node.getLength(); + if (nodeEnd < this.fStart || this.fEnd < nodeStart) { + return false; + } + if (nodeStart <= this.fStart && this.fEnd <= nodeEnd) { + this.fCoveringNode= node; + } + if (this.fStart <= nodeStart && nodeEnd <= this.fEnd) { + if (this.fCoveringNode == node) { // nodeStart == fStart && nodeEnd == fEnd + this.fCoveredNode= node; + return true; // look further for node with same length as parent + } else if (this.fCoveredNode == null) { // no better found + this.fCoveredNode= node; + } + return false; + } + return true; + } + /** + * Returns the covered node. If more than one nodes are covered by the selection, the + * returned node is first covered node found in a top-down traversal of the AST + * @return ASTNode + */ + public ASTNode getCoveredNode() { + return this.fCoveredNode; + } + + /** + * Returns the covering node. If more than one nodes are covering the selection, the + * returned node is last covering node found in a top-down traversal of the AST + * @return ASTNode + */ + public ASTNode getCoveringNode() { + return this.fCoveringNode; + } + } + /** + * Maps a selection to a given ASTNode, where the selection is defined using a start and a length. + * The result node is determined as follows: + *

+ * + * @param root the root node from which the search starts + * @param start the given start + * @param length the given length + * + * @return the found node + */ + public static ASTNode perform(ASTNode root, int start, int length) { + NodeFinder finder = new NodeFinder(root, start, length); + ASTNode result= finder.getCoveredNode(); + if (result == null || result.getStartPosition() != start || result.getLength() != length) { + return finder.getCoveringNode(); + } + return result; + } + + /** + * Maps a selection to a given ASTNode, where the selection is defined using a source range. + * It calls perform(root, range.getOffset(), range.getLength()). + * + * @return the result node + * @see #perform(ASTNode, int, int) + */ + public static ASTNode perform(ASTNode root, ISourceRange range) { + return perform(root, range.getOffset(), range.getLength()); + } + + /** + * Maps a selection to a given ASTNode, where the selection is given by a start and a length. + * The result node is determined as follows: + * + * + * @param root the root node from which the search starts + * @param start the given start + * @param length the given length + * @param source the source of the compilation unit + * + * @return the result node + * @throws JavaModelException if an error occurs in the Java model + */ + public static ASTNode perform(ASTNode root, int start, int length, ITypeRoot source) throws JavaModelException { + NodeFinder finder = new NodeFinder(root, start, length); + ASTNode result= finder.getCoveredNode(); + if (result == null) + return null; + int nodeStart= result.getStartPosition(); + if (start <= nodeStart && ((nodeStart + result.getLength()) <= (start + length))) { + IBuffer buffer= source.getBuffer(); + if (buffer != null) { + IScanner scanner= ToolFactory.createScanner(false, false, false, false); + scanner.setSource(buffer.getText(start, length).toCharArray()); + try { + int token= scanner.getNextToken(); + if (token != ITerminalSymbols.TokenNameEOF) { + int tStart= scanner.getCurrentTokenStartPosition(); + if (tStart == result.getStartPosition() - start) { + scanner.resetTo(tStart + result.getLength(), length - 1); + token= scanner.getNextToken(); + if (token == ITerminalSymbols.TokenNameEOF) + return result; + } + } + } catch (InvalidInputException e) { + // ignore + } + } + } + return finder.getCoveringNode(); + } + private ASTNode fCoveringNode; + private ASTNode fCoveredNode; + + /** + * Instantiate a new node finder using the given root node, the given start and the given length. + * + * @param root the given root node + * @param start the given start + * @param length the given length + */ + public NodeFinder(ASTNode root, int start, int length) { + NodeFinderVisitor nodeFinderVisitor = new NodeFinderVisitor(start, length); + root.accept(nodeFinderVisitor); + this.fCoveredNode = nodeFinderVisitor.getCoveredNode(); + this.fCoveringNode = nodeFinderVisitor.getCoveringNode(); + } + /** + * Returns the covered node. If more than one nodes are covered by the selection, the + * returned node is first covered node found in a top-down traversal of the AST. + * + * @return the covered node + */ + public ASTNode getCoveredNode() { + return this.fCoveredNode; + } + + /** + * Returns the covering node. If more than one nodes are covering the selection, the + * returned node is last covering node found in a top-down traversal of the AST. + * + * @return the covering node + */ + public ASTNode getCoveringNode() { + return this.fCoveringNode; + } +}