1
2
3
4 package net.sourceforge.pmd.lang.ast;
5
6 import java.util.ArrayList;
7 import java.util.Iterator;
8 import java.util.List;
9
10 import javax.xml.parsers.DocumentBuilder;
11 import javax.xml.parsers.DocumentBuilderFactory;
12 import javax.xml.parsers.ParserConfigurationException;
13
14 import net.sourceforge.pmd.lang.ast.xpath.Attribute;
15 import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator;
16 import net.sourceforge.pmd.lang.dfa.DataFlowNode;
17
18 import org.jaxen.BaseXPath;
19 import org.jaxen.JaxenException;
20 import org.w3c.dom.Document;
21 import org.w3c.dom.Element;
22
23 public abstract class AbstractNode implements Node {
24
25 protected Node parent;
26 protected Node[] children;
27 protected int id;
28
29 private String image;
30 protected int beginLine = -1;
31 protected int endLine;
32 protected int beginColumn = -1;
33 protected int endColumn;
34 private DataFlowNode dataFlowNode;
35 private Object userData;
36
37 public AbstractNode(int id) {
38 this.id = id;
39 }
40
41 public AbstractNode(int id, int theBeginLine, int theEndLine, int theBeginColumn, int theEndColumn) {
42 this(id);
43
44 beginLine = theBeginLine;
45 endLine = theEndLine;
46 beginColumn = theBeginColumn;
47 endColumn = theEndColumn;
48 }
49
50 public boolean isSingleLine() {
51 return beginLine == endLine;
52 }
53
54 public void jjtOpen() {
55
56 }
57
58 public void jjtClose() {
59
60 }
61
62 public void jjtSetParent(Node parent) {
63 this.parent = parent;
64 }
65
66 public Node jjtGetParent() {
67 return parent;
68 }
69
70 public void jjtAddChild(Node child, int index) {
71 if (children == null) {
72 children = new Node[index + 1];
73 } else if (index >= children.length) {
74 Node[] newChildren = new Node[index + 1];
75 System.arraycopy(children, 0, newChildren, 0, children.length);
76 children = newChildren;
77 }
78 children[index] = child;
79 }
80
81 public Node jjtGetChild(int index) {
82 return children[index];
83 }
84
85 public int jjtGetNumChildren() {
86 return children == null ? 0 : children.length;
87 }
88
89 public int jjtGetId() {
90 return id;
91 }
92
93
94
95
96
97 @Override
98 public abstract String toString();
99
100 public String getImage() {
101 return image;
102 }
103
104 public void setImage(String image) {
105 this.image = image;
106 }
107
108 public boolean hasImageEqualTo(String image) {
109 return this.image != null && this.image.equals(image);
110 }
111
112 public int getBeginLine() {
113 return beginLine;
114 }
115
116 public void testingOnly__setBeginLine(int i) {
117 this.beginLine = i;
118 }
119
120 public int getBeginColumn() {
121 if (beginColumn != -1) {
122 return beginColumn;
123 } else {
124 if (children != null && children.length > 0) {
125 return children[0].getBeginColumn();
126 } else {
127 throw new RuntimeException("Unable to determine beginning line of Node.");
128 }
129 }
130 }
131
132 public void testingOnly__setBeginColumn(int i) {
133 this.beginColumn = i;
134 }
135
136 public int getEndLine() {
137 return endLine;
138 }
139
140 public void testingOnly__setEndLine(int i) {
141 this.endLine = i;
142 }
143
144 public int getEndColumn() {
145 return endColumn;
146 }
147
148 public void testingOnly__setEndColumn(int i) {
149 this.endColumn = i;
150 }
151
152 public DataFlowNode getDataFlowNode() {
153 if (this.dataFlowNode == null) {
154 if (this.parent != null) {
155 return parent.getDataFlowNode();
156 }
157 return null;
158 }
159 return dataFlowNode;
160 }
161
162 public void setDataFlowNode(DataFlowNode dataFlowNode) {
163 this.dataFlowNode = dataFlowNode;
164 }
165
166
167
168
169
170
171
172
173 public Node getNthParent(int n) {
174 if (n <= 0) {
175 throw new IllegalArgumentException();
176 }
177 Node result = this.jjtGetParent();
178 for (int i = 1; i < n; i++) {
179 if (result == null) {
180 return null;
181 }
182 result = result.jjtGetParent();
183 }
184 return result;
185 }
186
187
188
189
190
191
192
193 public <T> T getFirstParentOfType(Class<T> parentType) {
194 Node parentNode = jjtGetParent();
195 while (parentNode != null && parentNode.getClass() != parentType) {
196 parentNode = parentNode.jjtGetParent();
197 }
198 return (T) parentNode;
199 }
200
201
202
203
204
205
206
207 public <T> List<T> getParentsOfType(Class<T> parentType) {
208 List<T> parents = new ArrayList<T>();
209 Node parentNode = jjtGetParent();
210 while (parentNode != null) {
211 if (parentNode.getClass() == parentType) {
212 parents.add((T) parentNode);
213 }
214 parentNode = parentNode.jjtGetParent();
215 }
216 return parents;
217 }
218
219
220
221
222 public <T> List<T> findDescendantsOfType(Class<T> targetType) {
223 List<T> list = new ArrayList<T>();
224 findDescendantsOfType(this, targetType, list, true);
225 return list;
226 }
227
228
229
230
231 public <T> void findDescendantsOfType(Class<T> targetType, List<T> results, boolean crossBoundaries) {
232 findDescendantsOfType(this, targetType, results, crossBoundaries);
233 }
234
235 private static <T> void findDescendantsOfType(Node node, Class<T> targetType, List<T> results,
236 boolean crossFindBoundaries) {
237
238 if (!crossFindBoundaries && node.isFindBoundary()) {
239 return;
240 }
241
242 int n = node.jjtGetNumChildren();
243 for (int i = 0; i < n; i++) {
244 Node child = node.jjtGetChild(i);
245 if (child.getClass() == targetType) {
246 results.add((T) child);
247 }
248
249 findDescendantsOfType(child, targetType, results, crossFindBoundaries);
250 }
251 }
252
253
254
255
256 public <T> List<T> findChildrenOfType(Class<T> targetType) {
257 List<T> list = new ArrayList<T>();
258 int n = jjtGetNumChildren();
259 for (int i = 0; i < n; i++) {
260 Node child = jjtGetChild(i);
261 if (child.getClass() == targetType) {
262 list.add((T) child);
263 }
264 }
265 return list;
266 }
267
268 public boolean isFindBoundary() {
269 return false;
270 }
271
272 public Document getAsDocument() {
273 try {
274 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
275 DocumentBuilder db = dbf.newDocumentBuilder();
276 Document document = db.newDocument();
277 appendElement(document);
278 return document;
279 } catch (ParserConfigurationException pce) {
280 throw new RuntimeException(pce);
281 }
282 }
283
284 protected void appendElement(org.w3c.dom.Node parentNode) {
285 DocumentNavigator docNav = new DocumentNavigator();
286 Document ownerDocument = parentNode.getOwnerDocument();
287 if (ownerDocument == null) {
288
289 ownerDocument = (Document) parentNode;
290 }
291 String elementName = docNav.getElementName(this);
292 Element element = ownerDocument.createElement(elementName);
293 parentNode.appendChild(element);
294 for (Iterator<Attribute> iter = docNav.getAttributeAxisIterator(this); iter.hasNext();) {
295 Attribute attr = iter.next();
296 element.setAttribute(attr.getName(), attr.getStringValue());
297 }
298 for (Iterator<Node> iter = docNav.getChildAxisIterator(this); iter.hasNext();) {
299 AbstractNode child = (AbstractNode) iter.next();
300 child.appendElement(element);
301 }
302 }
303
304
305
306
307 public <T> T getFirstDescendantOfType(Class<T> descendantType) {
308 return getFirstDescendantOfType(descendantType, this);
309 }
310
311
312
313
314 public <T> T getFirstChildOfType(Class<T> childType) {
315 int n = jjtGetNumChildren();
316 for (int i = 0; i < n; i++) {
317 Node child = jjtGetChild(i);
318 if (child.getClass() == childType) {
319 return (T) child;
320 }
321 }
322 return null;
323 }
324
325 private static <T> T getFirstDescendantOfType(Class<T> descendantType, Node node) {
326 int n = node.jjtGetNumChildren();
327 for (int i = 0; i < n; i++) {
328 Node n1 = node.jjtGetChild(i);
329 if (n1.getClass() == descendantType) {
330 return (T) n1;
331 }
332 T n2 = getFirstDescendantOfType(descendantType, n1);
333 if (n2 != null) {
334 return n2;
335 }
336 }
337 return null;
338 }
339
340
341
342
343 public final <T> boolean hasDescendantOfType(Class<T> type) {
344 return getFirstDescendantOfType(type) != null;
345 }
346
347
348
349
350
351
352 public final boolean hasDecendantOfAnyType(Class<?>... types) {
353 for (Class<?> type : types) {
354 if (hasDescendantOfType(type)) return true;
355 }
356 return false;
357 }
358
359
360
361
362 public List findChildNodesWithXPath(String xpathString) throws JaxenException {
363 return new BaseXPath(xpathString, new DocumentNavigator()).selectNodes(this);
364 }
365
366
367
368
369 public boolean hasDescendantMatchingXPath(String xpathString) {
370 try {
371 return !findChildNodesWithXPath(xpathString).isEmpty();
372 } catch (JaxenException e) {
373 throw new RuntimeException("XPath expression " + xpathString + " failed: " + e.getLocalizedMessage(), e);
374 }
375 }
376
377
378
379
380 public Object getUserData() {
381 return userData;
382 }
383
384
385
386
387 public void setUserData(Object userData) {
388 this.userData = userData;
389 }
390 }