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