1
2 package net.sourceforge.pmd.ast;
3
4 import net.sourceforge.pmd.dfa.IDataFlowNode;
5 import net.sourceforge.pmd.jaxen.Attribute;
6 import net.sourceforge.pmd.jaxen.DocumentNavigator;
7 import net.sourceforge.pmd.symboltable.Scope;
8 import org.apache.xerces.dom.DocumentImpl;
9 import org.jaxen.BaseXPath;
10 import org.jaxen.JaxenException;
11 import org.w3c.dom.Document;
12 import org.w3c.dom.Element;
13
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17
18 public class SimpleNode implements Node {
19
20 protected Node parent;
21 protected Node[] children;
22 protected int id;
23 protected JavaParser parser;
24 private String image;
25 private int beginLine = -1;
26 private int endLine;
27 private int beginColumn = -1;
28 private int endColumn;
29 private Scope scope;
30 private boolean discardable;
31
32 private IDataFlowNode dataFlowNode;
33
34 public IDataFlowNode getDataFlowNode() {
35 if (this.dataFlowNode == null) {
36 if (this.parent != null) {
37 return ((SimpleNode) parent).getDataFlowNode();
38 }
39 return null;
40 }
41 return dataFlowNode;
42 }
43
44 public void discardIfNecessary() {
45 if (discardable) {
46 SimpleNode parent = (SimpleNode) this.jjtGetParent();
47 SimpleNode kid = (SimpleNode) this.jjtGetChild(0);
48 kid.jjtSetParent(parent);
49 parent.jjtReplaceChild(this, kid);
50 }
51 }
52
53 public void setDataFlowNode(IDataFlowNode dataFlowNode) {
54 this.dataFlowNode = dataFlowNode;
55 }
56
57 public void setDiscardable() {
58 this.discardable = true;
59 }
60
61 public void setUnDiscardable() {
62 this.discardable = false;
63 }
64
65 public SimpleNode(int i) {
66 id = i;
67 }
68
69 public SimpleNode(JavaParser p, int i) {
70 this(i);
71 parser = p;
72 }
73
74 public void jjtOpen() {
75 if (beginLine == -1 && parser.token.next != null) {
76 beginLine = parser.token.next.beginLine;
77 beginColumn = parser.token.next.beginColumn;
78 }
79 }
80
81 public void jjtClose() {
82 if (beginLine == -1 && (children == null || children.length == 0)) {
83 beginColumn = parser.token.beginColumn;
84 }
85 if (beginLine == -1) {
86 beginLine = parser.token.beginLine;
87 }
88 endLine = parser.token.endLine;
89 endColumn = parser.token.endColumn;
90 }
91
92 public void setScope(Scope scope) {
93 this.scope = scope;
94 }
95
96 public Scope getScope() {
97 if (scope == null) {
98 return ((SimpleNode) parent).getScope();
99 }
100 return scope;
101 }
102
103 public int getBeginLine() {
104 return beginLine;
105 }
106
107 public void testingOnly__setBeginLine(int i) {
108 this.beginLine = i;
109 }
110
111 public void testingOnly__setBeginColumn(int i) {
112 this.beginColumn = i;
113 }
114
115 public int getBeginColumn() {
116 if (beginColumn != -1) {
117 return beginColumn;
118 } else {
119 if ((children != null) && (children.length > 0)) {
120 return ((SimpleNode) children[0]).getBeginColumn();
121 } else {
122 throw new RuntimeException("Unable to determine begining line of Node.");
123 }
124 }
125 }
126
127 public String getImage() {
128 return image;
129 }
130
131 public void setImage(String image) {
132 this.image = image;
133 }
134
135 public int getEndLine() {
136 return endLine;
137 }
138
139 public int getEndColumn() {
140 return endColumn;
141 }
142
143 /***
144 * Traverses up the tree to find the first parent instance of type parentType
145 *
146 * @param parentType class which you want to find.
147 * @return Node of type parentType. Returns null if none found.
148 */
149 public Node getFirstParentOfType(Class parentType) {
150 Node parentNode = jjtGetParent();
151 while (parentNode != null && parentNode.getClass() != parentType) {
152 parentNode = parentNode.jjtGetParent();
153 }
154 return parentNode;
155 }
156
157 /***
158 * Traverses up the tree to find all of the parent instances of type parentType
159 *
160 * @param parentType classes which you want to find.
161 * @return List of parentType instances found.
162 */
163 public List getParentsOfType(Class parentType) {
164 List parents = new ArrayList();
165 Node parentNode = jjtGetParent();
166 while (parentNode != null) {
167 if (parentNode.getClass() == parentType) {
168 parents.add(parentNode);
169 }
170 parentNode = parentNode.jjtGetParent();
171 }
172 return parents;
173 }
174
175 public List findChildrenOfType(Class targetType) {
176 List list = new ArrayList();
177 findChildrenOfType(targetType, list);
178 return list;
179 }
180
181 public void findChildrenOfType(Class targetType, List results) {
182 findChildrenOfType(this, targetType, results, true);
183 }
184
185 public void findChildrenOfType(Class targetType, List results, boolean descendIntoNestedClasses) {
186 this.findChildrenOfType(this, targetType, results, descendIntoNestedClasses);
187 }
188
189 private void findChildrenOfType(Node node, Class targetType, List results, boolean descendIntoNestedClasses) {
190 if (node.getClass().equals(targetType)) {
191 results.add(node);
192 }
193
194 if (!descendIntoNestedClasses) {
195 if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) {
196 return;
197 }
198
199 if (node instanceof ASTClassOrInterfaceBodyDeclaration && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) {
200 return;
201 }
202 }
203
204 for (int i = 0; i < node.jjtGetNumChildren(); i++) {
205 Node child = node.jjtGetChild(i);
206 if (child.jjtGetNumChildren() > 0) {
207 findChildrenOfType(child, targetType, results, descendIntoNestedClasses);
208 } else {
209 if (child.getClass().equals(targetType)) {
210 results.add(child);
211 }
212 }
213 }
214 }
215
216 public void jjtSetParent(Node n) {
217 parent = n;
218 }
219
220 public Node jjtGetParent() {
221 return parent;
222 }
223
224 public void jjtReplaceChild(Node old, Node newNode) {
225 for (int i = 0; i < children.length; i++) {
226 if (children[i] == old) {
227 children[i] = newNode;
228 return;
229 }
230 }
231 throw new RuntimeException("PMD INTERNAL ERROR: SimpleNode.jjtReplaceChild called to replace a node, but couldn't find the old node");
232 }
233
234 public void jjtAddChild(Node n, int i) {
235 if (children == null) {
236 children = new Node[i + 1];
237 } else if (i >= children.length) {
238 Node c[] = new Node[i + 1];
239 System.arraycopy(children, 0, c, 0, children.length);
240 children = c;
241 }
242 children[i] = n;
243 }
244
245 public Node jjtGetChild(int i) {
246 return children[i];
247 }
248
249 public int jjtGetNumChildren() {
250 return (children == null) ? 0 : children.length;
251 }
252
253 /***
254 * Accept the visitor. *
255 */
256 public Object jjtAccept(JavaParserVisitor visitor, Object data) {
257 return visitor.visit(this, data);
258 }
259
260 /***
261 * Accept the visitor. *
262 */
263 public Object childrenAccept(JavaParserVisitor visitor, Object data) {
264 if (children != null) {
265 for (int i = 0; i < children.length; ++i) {
266 children[i].jjtAccept(visitor, data);
267 }
268 }
269 return data;
270 }
271
272
273
274
275
276
277
278 public String toString() {
279 return JavaParserTreeConstants.jjtNodeName[id];
280 }
281
282 public String toString(String prefix) {
283 return prefix + toString();
284 }
285
286 public Document asXml() {
287 Document document = new DocumentImpl();
288 appendElement(document);
289 return document;
290 }
291
292 protected void appendElement(org.w3c.dom.Node parentNode) {
293 DocumentNavigator docNav = new DocumentNavigator();
294 Document ownerDocument = parentNode.getOwnerDocument();
295 if( ownerDocument == null )
296 {
297
298 ownerDocument = (Document) parentNode;
299 }
300 String elementName = docNav.getElementName(this);
301 Element element = ownerDocument.createElement(elementName);
302 parentNode.appendChild( element );
303 for (Iterator iter = docNav.getAttributeAxisIterator(this); iter.hasNext();) {
304 Attribute attr = (Attribute) iter.next();
305 element.setAttribute(attr.getName(), attr.getValue());
306 }
307 for (Iterator iter = docNav.getChildAxisIterator(this); iter.hasNext();) {
308 SimpleNode child = (SimpleNode) iter.next();
309 child.appendElement(element);
310 }
311 }
312
313
314
315 public void dump(String prefix) {
316 System.out.println(toString(prefix) + (image == null ? "" : ":" + image));
317 dumpChildren(prefix);
318 }
319
320 protected void dumpChildren(String prefix) {
321 if (children != null) {
322 for (int i = 0; i < children.length; ++i) {
323 SimpleNode n = (SimpleNode) children[i];
324 if (n != null) {
325 n.dump(prefix + " ");
326 }
327 }
328 }
329 }
330
331
332 /***
333 * Traverses down the tree to find the first child instance of type childType
334 *
335 * @param childType class which you want to find.
336 * @return Node of type childType. Returns <code>null</code> if none found.
337 */
338 public Node getFirstChildOfType(Class childType) {
339 return getFirstChildOfType(childType, this);
340 }
341
342 private Node getFirstChildOfType(Class childType, Node node) {
343 for (int i = 0; i < node.jjtGetNumChildren(); i++) {
344 Node n = node.jjtGetChild(i);
345 if (n != null) {
346 if (n.getClass().equals(childType))
347 return n;
348 Node n2 = getFirstChildOfType(childType, n);
349 if (n2 != null)
350 return n2;
351 }
352 }
353 return null;
354 }
355
356 /***
357 * Finds if this node contains a child of the given type.
358 * This is an utility method that uses {@link #findChildrenOfType(Class)}
359 *
360 * @param type the node type to search
361 * @return <code>true</code> if there is at lease on child of the given type and <code>false</code> in any other case
362 */
363 public final boolean containsChildOfType(Class type) {
364 return !findChildrenOfType(type).isEmpty();
365 }
366
367 public List findChildNodesWithXPath(String xpathString) throws JaxenException {
368 return new BaseXPath(xpathString, new DocumentNavigator()).selectNodes(this);
369 }
370 }
371