1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package test.net.sourceforge.pmd.ast;
5   
6   import net.sourceforge.pmd.PMD;
7   import net.sourceforge.pmd.ast.ASTAssignmentOperator;
8   import net.sourceforge.pmd.ast.ASTBlock;
9   import net.sourceforge.pmd.ast.ASTBlockStatement;
10  import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
11  import net.sourceforge.pmd.ast.ASTCompilationUnit;
12  import net.sourceforge.pmd.ast.ASTEqualityExpression;
13  import net.sourceforge.pmd.ast.ASTExpression;
14  import net.sourceforge.pmd.ast.ASTExtendsList;
15  import net.sourceforge.pmd.ast.ASTFieldDeclaration;
16  import net.sourceforge.pmd.ast.ASTImplementsList;
17  import net.sourceforge.pmd.ast.ASTInstanceOfExpression;
18  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
19  import net.sourceforge.pmd.ast.ASTName;
20  import net.sourceforge.pmd.ast.ASTRelationalExpression;
21  import net.sourceforge.pmd.ast.ASTReturnStatement;
22  import net.sourceforge.pmd.ast.ASTStatement;
23  import net.sourceforge.pmd.ast.ASTVariableInitializer;
24  import net.sourceforge.pmd.ast.Node;
25  import net.sourceforge.pmd.ast.SimpleNode;
26  import org.apache.xml.serialize.OutputFormat;
27  import org.apache.xml.serialize.XMLSerializer;
28  import org.w3c.dom.Document;
29  import test.net.sourceforge.pmd.testframework.ParserTst;
30  
31  import java.io.IOException;
32  import java.io.StringWriter;
33  import java.util.ArrayList;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Set;
37  
38  public class SimpleNodeTest extends ParserTst {
39  
40      public void testMethodDiffLines() throws Throwable {
41          Set methods = getNodes(ASTMethodDeclaration.class, METHOD_DIFF_LINES);
42          Iterator iter = methods.iterator();
43          verifyNode((SimpleNode) iter.next(), 2, 9, 4, 2);
44      }
45  
46      public void testMethodSameLine() throws Throwable {
47          Set methods = getNodes(ASTMethodDeclaration.class, METHOD_SAME_LINE);
48          verifyNode((SimpleNode) methods.iterator().next(), 2, 9, 2, 21);
49      }
50  
51      public void testNoLookahead() throws Throwable {
52          String code = NO_LOOKAHEAD; // 1, 8 -> 1, 20
53          Set uCD = getNodes(ASTClassOrInterfaceDeclaration.class, code);
54          verifyNode((SimpleNode) uCD.iterator().next(), 1, 8, 1, 20);
55      }
56  
57      public void testHasExplicitExtends() throws Throwable {
58          String code = HAS_EXPLICIT_EXTENDS;
59          ASTClassOrInterfaceDeclaration ucd = (ASTClassOrInterfaceDeclaration) (getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next());
60          assertTrue(ucd.jjtGetChild(0) instanceof ASTExtendsList);
61      }
62  
63      public void testNoExplicitExtends() throws Throwable {
64          String code = NO_EXPLICIT_EXTENDS;
65          ASTClassOrInterfaceDeclaration ucd = (ASTClassOrInterfaceDeclaration) (getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next());
66          assertFalse(ucd.jjtGetChild(0) instanceof ASTExtendsList);
67      }
68  
69      public void testHasExplicitImplements() throws Throwable {
70          String code = HAS_EXPLICIT_IMPLEMENTS;
71          ASTClassOrInterfaceDeclaration ucd = (ASTClassOrInterfaceDeclaration) (getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next());
72          assertTrue(ucd.jjtGetChild(0) instanceof ASTImplementsList);
73      }
74  
75      public void testNoExplicitImplements() throws Throwable {
76          String code = NO_EXPLICIT_IMPLEMENTS;
77          ASTClassOrInterfaceDeclaration ucd = (ASTClassOrInterfaceDeclaration) (getNodes(ASTClassOrInterfaceDeclaration.class, code).iterator().next());
78          assertFalse(ucd.jjtGetChild(0) instanceof ASTImplementsList);
79      }
80  
81      public void testColumnsOnQualifiedName() throws Throwable {
82          Set name = getNodes(ASTName.class, QUALIFIED_NAME);
83          Iterator i = name.iterator();
84          while (i.hasNext()) {
85              SimpleNode node = (SimpleNode) i.next();
86              if (node.getImage().equals("java.io.File")) {
87                  verifyNode(node, 1, 8, 1, 19);
88              }
89          }
90      }
91  
92      public void testLineNumbersForNameSplitOverTwoLines() throws Throwable {
93          Set name = getNodes(ASTName.class, BROKEN_LINE_IN_NAME);
94          Iterator i = name.iterator();
95          while (i.hasNext()) {
96              SimpleNode node = (SimpleNode) i.next();
97              if (node.getImage().equals("java.io.File")) {
98                  verifyNode(node, 1, 8, 2, 4);
99              }
100             if (node.getImage().equals("Foo")) {
101                 verifyNode(node, 2, 15, 2, 18);
102             }
103         }
104     }
105 
106     public void testLineNumbersAreSetOnAllSiblings() throws Throwable {
107         Set blocks = getNodes(ASTBlock.class, LINE_NUMBERS_ON_SIBLINGS);
108         Iterator i = blocks.iterator();
109         while (i.hasNext()) {
110             ASTBlock b = (ASTBlock) i.next();
111             assertTrue(b.getBeginLine() > 0);
112         }
113         blocks = getNodes(ASTVariableInitializer.class, LINE_NUMBERS_ON_SIBLINGS);
114         i = blocks.iterator();
115         while (i.hasNext()) {
116             ASTVariableInitializer b = (ASTVariableInitializer) i.next();
117             assertTrue(b.getBeginLine() > 0);
118         }
119         blocks = getNodes(ASTExpression.class, LINE_NUMBERS_ON_SIBLINGS);
120         i = blocks.iterator();
121         while (i.hasNext()) {
122             ASTExpression b = (ASTExpression) i.next();
123             assertTrue(b.getBeginLine() > 0);
124         }
125     }
126 
127     public void testFindChildrenOfType() {
128         ASTBlock block = new ASTBlock(2);
129         block.jjtAddChild(new ASTReturnStatement(1), 0);
130         assertEquals(1, block.findChildrenOfType(ASTReturnStatement.class).size());
131     }
132 
133     public void testFindChildrenOfTypeMultiple() {
134         ASTBlock block = new ASTBlock(1);
135         block.jjtAddChild(new ASTBlockStatement(2), 0);
136         block.jjtAddChild(new ASTBlockStatement(3), 1);
137         List nodes = new ArrayList();
138         block.findChildrenOfType(ASTBlockStatement.class, nodes);
139         assertEquals(2, nodes.size());
140     }
141 
142     public void testFindChildrenOfTypeRecurse() {
143         ASTBlock block = new ASTBlock(1);
144         ASTBlock childBlock = new ASTBlock(2);
145         block.jjtAddChild(childBlock, 0);
146         childBlock.jjtAddChild(new ASTMethodDeclaration(3), 0);
147         List nodes = new ArrayList();
148         block.findChildrenOfType(ASTMethodDeclaration.class, nodes);
149         assertEquals(1, nodes.size());
150     }
151 
152     public void testReplaceChild() {
153         ASTEqualityExpression ee = new ASTEqualityExpression(1);
154         ASTInstanceOfExpression io1 = new ASTInstanceOfExpression(2);
155         ASTRelationalExpression re = new ASTRelationalExpression(3);
156         ASTInstanceOfExpression io2 = new ASTInstanceOfExpression(2);
157         ee.jjtAddChild(io1, 0);
158         ee.jjtAddChild(io2, 1);
159         io1.jjtAddChild(re, 0);
160         ee.jjtReplaceChild(io1, re);
161         assertEquals(ee.jjtGetChild(0), re);
162         assertEquals(ee.jjtGetChild(1), io2);
163     }
164 
165     public void testGetFirstChild() {
166         ASTBlock block = new ASTBlock(1);
167         ASTStatement x = new ASTStatement(2);
168         block.jjtAddChild(x, 0);
169         block.jjtAddChild(new ASTStatement(3), 1);
170 
171         Node n = block.getFirstChildOfType(ASTStatement.class);
172         assertNotNull(n);
173         assertTrue(n instanceof ASTStatement);
174         assertEquals(x, n);
175     }
176 
177     public void testGetFirstChildNested() {
178         ASTBlock block = new ASTBlock(1);
179         ASTStatement x = new ASTStatement(2);
180         ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
181         x.jjtAddChild(x1, 1);
182         block.jjtAddChild(x, 0);
183         block.jjtAddChild(new ASTStatement(3), 1);
184 
185         Node n = block.getFirstChildOfType(ASTAssignmentOperator.class);
186         assertNotNull(n);
187         assertTrue(n instanceof ASTAssignmentOperator);
188         assertEquals(x1, n);
189     }
190 
191     public void testGetFirstChildNestedDeeper() {
192         ASTBlock block = new ASTBlock(1);
193         ASTStatement x = new ASTStatement(2);
194         ASTAssignmentOperator x1 = new ASTAssignmentOperator(4);
195         ASTName x2 = new ASTName(5);
196 
197         x.jjtAddChild(x1, 1);
198         x1.jjtAddChild(x2, 0);
199         block.jjtAddChild(x, 0);
200         block.jjtAddChild(new ASTStatement(3), 1);
201 
202         Node n = block.getFirstChildOfType(ASTName.class);
203         assertNotNull(n);
204         assertTrue(n instanceof ASTName);
205         assertEquals(x2, n);
206     }
207 
208 /*
209     public void testContainsNoInner() throws Throwable {
210         ASTCompilationUnit c = (ASTCompilationUnit) getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER).iterator().next();
211         List res = new ArrayList();
212         c.findChildrenOfType(ASTFieldDeclaration.class, res, false);
213         assertTrue(res.isEmpty());
214         String expectedXml = "<CompilationUnit BeginColumn=\"1\" BeginLine=\"5\" EndColumn=\"1\" EndLine=\"5\">" +
215                 "<TypeDeclaration BeginColumn=\"1\" BeginLine=\"1\" EndColumn=\"1\" EndLine=\"5\">" +
216                 "<ClassOrInterfaceDeclaration Abstract=\"false\" BeginColumn=\"8\" BeginLine=\"1\" EndColumn=\"1\" " +
217                 "EndLine=\"5\" Final=\"false\" Image=\"Test\" Interface=\"false\" Native=\"false\" Nested=\"false\" PackagePrivate=\"false\" Private=\"false\" Protected=\"false\" Public=\"true\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" Volatile=\"false\">" +
218                 "<ClassOrInterfaceBody BeginColumn=\"19\" BeginLine=\"1\" EndColumn=\"1\" EndLine=\"5\">" +
219                 "<ClassOrInterfaceBodyDeclaration AnonymousInnerClass=\"false\" BeginColumn=\"3\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\">" +
220                 "<ClassOrInterfaceDeclaration Abstract=\"false\" BeginColumn=\"10\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\" Final=\"false\" " +
221                 "Image=\"Inner\" Interface=\"false\" Native=\"false\" Nested=\"true\" PackagePrivate=\"false\" Private=\"false\" Protected=\"false\" " +
222                 "Public=\"true\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" Volatile=\"false\">" +
223                 "<ClassOrInterfaceBody BeginColumn=\"22\" BeginLine=\"2\" EndColumn=\"3\" EndLine=\"4\">" +
224                 "<ClassOrInterfaceBodyDeclaration AnonymousInnerClass=\"false\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"11\" EndLine=\"3\">" +
225                 "<FieldDeclaration Abstract=\"false\" Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"11\" EndLine=\"3\" Final=\"false\" Native=\"false\" PackagePrivate=\"true\" Private=\"false\" Protected=\"false\" Public=\"false\" Static=\"false\" Strictfp=\"false\" Synchronized=\"false\" Transient=\"false\" VariableName=\"foo\" Volatile=\"false\"><Type Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" EndColumn=\"6\" EndLine=\"3\">" +
226                 "<PrimitiveType Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"4\" BeginLine=\"3\" Boolean=\"false\" EndColumn=\"6\" EndLine=\"3\" Image=\"int\"/>" +
227                 "</Type>" +
228                 "<VariableDeclarator BeginColumn=\"8\" BeginLine=\"3\" EndColumn=\"10\" EndLine=\"3\">" +
229                 "<VariableDeclaratorId Array=\"false\" ArrayDepth=\"0\" BeginColumn=\"8\" BeginLine=\"3\" EndColumn=\"10\" EndLine=\"3\" ExceptionBlockParameter=\"false\" Image=\"foo\"/>" +
230                 "</VariableDeclarator></FieldDeclaration></ClassOrInterfaceBodyDeclaration></ClassOrInterfaceBody>" +
231                 "</ClassOrInterfaceDeclaration></ClassOrInterfaceBodyDeclaration></ClassOrInterfaceBody></ClassOrInterfaceDeclaration>" +
232                 "</TypeDeclaration></CompilationUnit>";
233         assertEquals( expectedXml, getXmlString( c ) );
234     }
235 */
236 
237     public void testContainsNoInnerWithAnonInner() throws Throwable {
238         ASTCompilationUnit c = (ASTCompilationUnit) getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER_WITH_ANON_INNER).iterator().next();
239         List res = new ArrayList();
240         c.findChildrenOfType(ASTFieldDeclaration.class, res, false);
241         assertTrue(res.isEmpty());
242     }
243 
244     public void testContainsChildOfType() throws Throwable {
245         ASTClassOrInterfaceDeclaration c = (ASTClassOrInterfaceDeclaration) getNodes(ASTClassOrInterfaceDeclaration.class, CONTAINS_CHILDREN_OF_TYPE).iterator().next();
246         assertTrue(c.containsChildOfType(ASTFieldDeclaration.class));
247     }
248 
249     public void testXPathNodeSelect() throws Throwable {
250         ASTClassOrInterfaceDeclaration c = (ASTClassOrInterfaceDeclaration) getNodes(ASTClassOrInterfaceDeclaration.class, TEST_XPATH).iterator().next();
251         List nodes = c.findChildNodesWithXPath("//FieldDeclaration");
252         assertEquals(2, nodes.size());
253         assertTrue(nodes.get(0) instanceof ASTFieldDeclaration);
254     }
255 
256     private void verifyNode(SimpleNode node, int beginLine, int beginCol, int endLine, int endCol) {
257         assertEquals("Unexpected beginning line: ", beginLine, node.getBeginLine());
258         assertEquals("Unexpected beginning column: ", beginCol, node.getBeginColumn());
259         assertEquals("Unexpected ending line:", endLine, node.getEndLine());
260         assertEquals("Unexpected ending column:", endCol, node.getEndColumn());
261     }
262 
263     private static final String HAS_EXPLICIT_EXTENDS =
264             "public class Test extends Foo {}";
265 
266     private static final String NO_EXPLICIT_EXTENDS =
267             "public class Test {}";
268 
269     private static final String HAS_EXPLICIT_IMPLEMENTS =
270             "public class Test implements Foo {}";
271 
272     private static final String NO_EXPLICIT_IMPLEMENTS =
273             "public class Test {}";
274 
275     private static final String METHOD_SAME_LINE =
276             "public class Test {" + PMD.EOL +
277             " public void foo() {}" + PMD.EOL +
278             "}";
279 
280     private static final String QUALIFIED_NAME =
281             "import java.io.File;" + PMD.EOL +
282             "public class Foo{}";
283 
284     private static final String BROKEN_LINE_IN_NAME =
285             "import java.io." + PMD.EOL +
286             "File;" + PMD.EOL +
287             "public class Foo{}";
288 
289     private static final String LINE_NUMBERS_ON_SIBLINGS =
290             "public class Foo {" + PMD.EOL +
291             " void bar() {" + PMD.EOL +
292             "  try {" + PMD.EOL +
293             "  } catch (Exception1 e) {" + PMD.EOL +
294             "   int x =2;" + PMD.EOL +
295             "  }" + PMD.EOL +
296             " if (x != null) {}" + PMD.EOL +
297             " }" + PMD.EOL +
298             "}";
299 
300     private static final String NO_LOOKAHEAD = "public class Foo { }";
301 
302     private static final String METHOD_DIFF_LINES =
303             "public class Test {" + PMD.EOL +
304             " public void foo() {" + PMD.EOL +
305             "  int x;" + PMD.EOL +
306             " }" + PMD.EOL +
307             "}";
308 
309     private static final String CONTAINS_CHILDREN_OF_TYPE =
310             "public class Test {" + PMD.EOL +
311             "  int x;" + PMD.EOL +
312             "}";
313 
314     private static final String CONTAINS_NO_INNER =
315             "public class Test {" + PMD.EOL +
316             "  public class Inner {" + PMD.EOL +
317             "   int foo;" + PMD.EOL +
318             "  }" + PMD.EOL +
319             "}";
320 
321     private static final String CONTAINS_NO_INNER_WITH_ANON_INNER =
322             "public class Test {" + PMD.EOL +
323             "  void bar() {" + PMD.EOL +
324             "   foo(new Fuz() { int x = 2;});" + PMD.EOL +
325             "  }" + PMD.EOL +
326             "}";
327 
328     private static final String TEST_XPATH =
329             "public class Test {" + PMD.EOL +
330             "  int x = 2;" + PMD.EOL +
331             "  int y = 42;" + PMD.EOL +
332             "}";
333 
334 }