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