View Javadoc

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