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