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