Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2000, 2008 IBM Corporation and others. |
3 |
* All rights reserved. This program and the accompanying materials |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
5 |
* which accompanies this distribution, and is available at |
6 |
* http://www.eclipse.org/legal/epl-v10.html |
7 |
* |
8 |
* Contributors: |
9 |
* IBM Corporation - initial API and implementation |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.jdt.core.dom; |
12 |
|
13 |
import org.eclipse.jdt.core.IBuffer; |
14 |
import org.eclipse.jdt.core.ISourceRange; |
15 |
import org.eclipse.jdt.core.ITypeRoot; |
16 |
import org.eclipse.jdt.core.JavaModelException; |
17 |
import org.eclipse.jdt.core.ToolFactory; |
18 |
import org.eclipse.jdt.core.compiler.IScanner; |
19 |
import org.eclipse.jdt.core.compiler.ITerminalSymbols; |
20 |
import org.eclipse.jdt.core.compiler.InvalidInputException; |
21 |
|
22 |
/** |
23 |
* For a given range, finds the covered node and the covering node. |
24 |
* |
25 |
* @since 3.5 |
26 |
*/ |
27 |
public final class NodeFinder { |
28 |
/** |
29 |
* This class defines the actual visitor that finds the node. |
30 |
*/ |
31 |
private static class NodeFinderVisitor extends ASTVisitor { |
32 |
private int fStart; |
33 |
private int fEnd; |
34 |
private ASTNode fCoveringNode; |
35 |
private ASTNode fCoveredNode; |
36 |
|
37 |
NodeFinderVisitor(int offset, int length) { |
38 |
super(true); // include Javadoc tags |
39 |
this.fStart= offset; |
40 |
this.fEnd= offset + length; |
41 |
} |
42 |
|
43 |
public boolean preVisit2(ASTNode node) { |
44 |
int nodeStart= node.getStartPosition(); |
45 |
int nodeEnd= nodeStart + node.getLength(); |
46 |
if (nodeEnd < this.fStart || this.fEnd < nodeStart) { |
47 |
return false; |
48 |
} |
49 |
if (nodeStart <= this.fStart && this.fEnd <= nodeEnd) { |
50 |
this.fCoveringNode= node; |
51 |
} |
52 |
if (this.fStart <= nodeStart && nodeEnd <= this.fEnd) { |
53 |
if (this.fCoveringNode == node) { // nodeStart == fStart && nodeEnd == fEnd |
54 |
this.fCoveredNode= node; |
55 |
return true; // look further for node with same length as parent |
56 |
} else if (this.fCoveredNode == null) { // no better found |
57 |
this.fCoveredNode= node; |
58 |
} |
59 |
return false; |
60 |
} |
61 |
return true; |
62 |
} |
63 |
/** |
64 |
* Returns the covered node. If more than one nodes are covered by the selection, the |
65 |
* returned node is first covered node found in a top-down traversal of the AST |
66 |
* @return ASTNode |
67 |
*/ |
68 |
public ASTNode getCoveredNode() { |
69 |
return this.fCoveredNode; |
70 |
} |
71 |
|
72 |
/** |
73 |
* Returns the covering node. If more than one nodes are covering the selection, the |
74 |
* returned node is last covering node found in a top-down traversal of the AST |
75 |
* @return ASTNode |
76 |
*/ |
77 |
public ASTNode getCoveringNode() { |
78 |
return this.fCoveringNode; |
79 |
} |
80 |
} |
81 |
/** |
82 |
* Maps a selection to a given ASTNode, where the selection is defined using a start and a length. |
83 |
* The result node is determined as follows: |
84 |
* <ul> |
85 |
* <li>first the visitor tries to find a node with the exact <code>start</code> and <code>length</code></li> |
86 |
* <li>if no such node exists than the node that encloses the range defined by |
87 |
* <code>start</code> and <code>length</code> is returned.</li> |
88 |
* <li>if the length is zero than also nodes are considered where the node's |
89 |
* start or end position matches <code>start</code>.</li> |
90 |
* <li>otherwise <code>null</code> is returned.</li> |
91 |
* </ul> |
92 |
* |
93 |
* @param root the root node from which the search starts |
94 |
* @param start the given start |
95 |
* @param length the given length |
96 |
* |
97 |
* @return the found node |
98 |
*/ |
99 |
public static ASTNode perform(ASTNode root, int start, int length) { |
100 |
NodeFinder finder = new NodeFinder(root, start, length); |
101 |
ASTNode result= finder.getCoveredNode(); |
102 |
if (result == null || result.getStartPosition() != start || result.getLength() != length) { |
103 |
return finder.getCoveringNode(); |
104 |
} |
105 |
return result; |
106 |
} |
107 |
|
108 |
/** |
109 |
* Maps a selection to a given ASTNode, where the selection is defined using a source range. |
110 |
* It calls <code>perform(root, range.getOffset(), range.getLength())</code>. |
111 |
* |
112 |
* @return the result node |
113 |
* @see #perform(ASTNode, int, int) |
114 |
*/ |
115 |
public static ASTNode perform(ASTNode root, ISourceRange range) { |
116 |
return perform(root, range.getOffset(), range.getLength()); |
117 |
} |
118 |
|
119 |
/** |
120 |
* Maps a selection to a given ASTNode, where the selection is given by a start and a length. |
121 |
* The result node is determined as follows: |
122 |
* <ul> |
123 |
* <li>first the visitor tries to find a node that is covered by <code>start</code> and |
124 |
* <code>length</code> where either <code>start</code> and <code>length</code> exactly |
125 |
* matches the node or where the text covered before and after the node only consists |
126 |
* of white spaces or comments.</li> |
127 |
* <li>if no such node exists than the node that encloses the range defined by |
128 |
* <code>start</code> and <code>length</code> is returned.</li> |
129 |
* <li>if the length is zero than also nodes are considered where the node's |
130 |
* start or end position matches <code>start</code>.</li> |
131 |
* <li>otherwise <code>null</code> is returned.</li> |
132 |
* </ul> |
133 |
* |
134 |
* @param root the root node from which the search starts |
135 |
* @param start the given start |
136 |
* @param length the given length |
137 |
* @param source the source of the compilation unit |
138 |
* |
139 |
* @return the result node |
140 |
* @throws JavaModelException if an error occurs in the Java model |
141 |
*/ |
142 |
public static ASTNode perform(ASTNode root, int start, int length, ITypeRoot source) throws JavaModelException { |
143 |
NodeFinder finder = new NodeFinder(root, start, length); |
144 |
ASTNode result= finder.getCoveredNode(); |
145 |
if (result == null) |
146 |
return null; |
147 |
int nodeStart= result.getStartPosition(); |
148 |
if (start <= nodeStart && ((nodeStart + result.getLength()) <= (start + length))) { |
149 |
IBuffer buffer= source.getBuffer(); |
150 |
if (buffer != null) { |
151 |
IScanner scanner= ToolFactory.createScanner(false, false, false, false); |
152 |
scanner.setSource(buffer.getText(start, length).toCharArray()); |
153 |
try { |
154 |
int token= scanner.getNextToken(); |
155 |
if (token != ITerminalSymbols.TokenNameEOF) { |
156 |
int tStart= scanner.getCurrentTokenStartPosition(); |
157 |
if (tStart == result.getStartPosition() - start) { |
158 |
scanner.resetTo(tStart + result.getLength(), length - 1); |
159 |
token= scanner.getNextToken(); |
160 |
if (token == ITerminalSymbols.TokenNameEOF) |
161 |
return result; |
162 |
} |
163 |
} |
164 |
} catch (InvalidInputException e) { |
165 |
// ignore |
166 |
} |
167 |
} |
168 |
} |
169 |
return finder.getCoveringNode(); |
170 |
} |
171 |
private ASTNode fCoveringNode; |
172 |
private ASTNode fCoveredNode; |
173 |
|
174 |
/** |
175 |
* Instantiate a new node finder using the given root node, the given start and the given length. |
176 |
* |
177 |
* @param root the given root node |
178 |
* @param start the given start |
179 |
* @param length the given length |
180 |
*/ |
181 |
public NodeFinder(ASTNode root, int start, int length) { |
182 |
NodeFinderVisitor nodeFinderVisitor = new NodeFinderVisitor(start, length); |
183 |
root.accept(nodeFinderVisitor); |
184 |
this.fCoveredNode = nodeFinderVisitor.getCoveredNode(); |
185 |
this.fCoveringNode = nodeFinderVisitor.getCoveringNode(); |
186 |
} |
187 |
/** |
188 |
* Returns the covered node. If more than one nodes are covered by the selection, the |
189 |
* returned node is first covered node found in a top-down traversal of the AST. |
190 |
* |
191 |
* @return the covered node |
192 |
*/ |
193 |
public ASTNode getCoveredNode() { |
194 |
return this.fCoveredNode; |
195 |
} |
196 |
|
197 |
/** |
198 |
* Returns the covering node. If more than one nodes are covering the selection, the |
199 |
* returned node is last covering node found in a top-down traversal of the AST. |
200 |
* |
201 |
* @return the covering node |
202 |
*/ |
203 |
public ASTNode getCoveringNode() { |
204 |
return this.fCoveringNode; |
205 |
} |
206 |
} |