View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.symboltable;
5   
6   import static org.junit.Assert.assertEquals;
7   import static org.junit.Assert.assertFalse;
8   import static org.junit.Assert.assertTrue;
9   import static org.junit.Assert.fail;
10  
11  import java.util.Iterator;
12  import java.util.List;
13  import java.util.Map;
14  
15  import net.sourceforge.pmd.PMD;
16  import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
17  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
18  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
19  import net.sourceforge.pmd.lang.java.ast.DummyJavaNode;
20  import net.sourceforge.pmd.lang.java.ast.JavaNode;
21  import net.sourceforge.pmd.lang.java.symboltable.ClassNameDeclaration;
22  import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
23  import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
24  import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
25  import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
26  import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
27  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
28  
29  import org.junit.Test;
30  public class ClassScopeTest extends STBBaseTst {
31  
32      @Test
33      public void testEnumsClassScope() {
34          parseCode15(ENUM_SCOPE);
35      }
36  
37      @Test
38      public void testEnumTypeParameter() {
39          parseCode15(ENUM_TYPE_PARAMETER);
40      }
41  
42      @Test
43      public void testVarArgsEmpty() {
44          parseCode15(
45                  "public class Foo {\n" +
46                  "  public void bar1(String s, Integer... i) {}\n" +
47                  "  public void bar1() {}\n" +
48                  "  public void c() {\n" +
49                  "    bar1();\n" +
50                  "  }\n" +
51                  "}\n"
52          );
53      }
54  
55      // FIXME - these will break when this goes from Anonymous$1 to Foo$1
56      @Test
57      public void testAnonymousInnerClassName() {
58          ClassScope s = new ClassScope("Foo");
59          s = new ClassScope();
60          assertEquals("Anonymous$1", s.getClassName());
61          s = new ClassScope();
62          assertEquals("Anonymous$2", s.getClassName());
63      }
64  
65      @Test
66      public void testContains() {
67          ClassScope s = new ClassScope("Foo");
68          ASTVariableDeclaratorId node = new ASTVariableDeclaratorId(1);
69          node.setImage("bar");
70          s.addDeclaration(new VariableNameDeclaration(node));
71          assertTrue(s.getDeclarations().keySet().iterator().hasNext());
72      }
73  
74      @Test
75      public void testCantContainsSuperToString() {
76          ClassScope s = new ClassScope("Foo");
77          JavaNode node = new DummyJavaNode(1);
78          node.setImage("super.toString");
79          assertFalse(s.contains(new JavaNameOccurrence(node, node.getImage())));
80      }
81  
82      @Test
83      public void testContainsStaticVariablePrefixedWithClassName() {
84          ClassScope s = new ClassScope("Foo");
85          ASTVariableDeclaratorId node = new ASTVariableDeclaratorId(1);
86          node.setImage("X");
87          s.addDeclaration(new VariableNameDeclaration(node));
88  
89          JavaNode node2 = new DummyJavaNode(2);
90          node2.setImage("Foo.X");
91          assertTrue(s.contains(new JavaNameOccurrence(node2, node2.getImage())));
92      }
93  
94      @Test
95      public void testClassName() {
96          parseCode(CLASS_NAME);
97          ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
98          assertEquals("Foo", n.getScope().getEnclosingScope(ClassScope.class).getClassName());
99      }
100 
101     @Test
102     public void testMethodDeclarationRecorded() {
103         parseCode(METHOD_DECLARATIONS_RECORDED);
104         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
105         ClassScope s = (ClassScope) n.getScope();
106         Map m = s.getDeclarations();
107         assertEquals(1, m.size());
108         MethodNameDeclaration mnd = (MethodNameDeclaration) m.keySet().iterator().next();
109         assertEquals("bar", mnd.getImage());
110         ASTMethodDeclaration node = (ASTMethodDeclaration) mnd.getNode().jjtGetParent();
111         assertTrue(node.isPrivate());
112     }
113 
114     @Test
115     public void testTwoMethodsSameNameDiffArgs() {
116         // TODO this won't work with String and java.lang.String
117         parseCode(METHODS_WITH_DIFF_ARG);
118         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
119         Map m = ((ClassScope) n.getScope()).getDeclarations();
120         assertEquals(2, m.size());
121         Iterator i = m.keySet().iterator();
122         MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
123         assertEquals("bar", mnd.getImage());
124         assertEquals("bar", ((MethodNameDeclaration) i.next()).getImage());
125     }
126 
127 
128     @Test
129     public final void testOneParam() throws Throwable {
130         parseCode(ONE_PARAM);
131         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
132         Map m = ((ClassScope) n.getScope()).getDeclarations();
133         MethodNameDeclaration mnd = (MethodNameDeclaration) m.keySet().iterator().next();
134         assertEquals("(String)", mnd.getParameterDisplaySignature());
135     }
136 
137     @Test
138     public final void testTwoParams() throws Throwable {
139         parseCode(TWO_PARAMS);
140         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
141         Map m = ((ClassScope) n.getScope()).getDeclarations();
142         MethodNameDeclaration mnd = (MethodNameDeclaration) m.keySet().iterator().next();
143         assertEquals("(String,int)", mnd.getParameterDisplaySignature());
144     }
145 
146     @Test
147     public final void testNoParams() throws Throwable {
148         parseCode(NO_PARAMS);
149         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
150         Map m = ((ClassScope) n.getScope()).getDeclarations();
151         MethodNameDeclaration mnd = (MethodNameDeclaration) m.keySet().iterator().next();
152         assertEquals("()", mnd.getParameterDisplaySignature());
153     }
154 
155     @Test
156     public final void testOneParamVararg() throws Throwable {
157     	parseCode15(ONE_PARAM_VARARG);
158         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
159         Map m = ((ClassScope) n.getScope()).getDeclarations();
160         MethodNameDeclaration mnd = (MethodNameDeclaration) m.keySet().iterator().next();
161         assertEquals("(String...)", mnd.getParameterDisplaySignature());
162     }
163 
164     @Test
165     public final void testTwoParamsVararg() throws Throwable {
166     	parseCode15(TWO_PARAMS_VARARG);
167         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
168         Map m = ((ClassScope) n.getScope()).getDeclarations();
169         MethodNameDeclaration mnd = (MethodNameDeclaration) m.keySet().iterator().next();
170         assertEquals("(String,String...)", mnd.getParameterDisplaySignature());
171     }
172 
173 
174     @Test
175     public final void testNestedClassDeclFound() throws Throwable {
176         parseCode(NESTED_CLASS_FOUND);
177         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
178         ClassScope c = (ClassScope) n.getScope();
179         Map m = c.getDeclarations();
180         ClassNameDeclaration cnd = (ClassNameDeclaration) m.keySet().iterator().next();
181         assertEquals("Buz", cnd.getImage());
182     }
183 
184     @Test
185     public final void testbuz() throws Throwable {
186         parseCode(METH);
187         //SymbolTableViewer st = new SymbolTableViewer();
188         //acu.jjtAccept(st, null);
189     }
190 
191     @Test
192     public void testMethodUsageSeen() {
193         parseCode(METHOD_USAGE_SEEN);
194         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
195         Map m = ((ClassScope) n.getScope()).getDeclarations();
196         Iterator i = m.entrySet().iterator();
197         MethodNameDeclaration mnd;
198         Map.Entry entry;
199         
200         do {
201             entry = (Map.Entry) i.next();
202             mnd = (MethodNameDeclaration) entry.getKey();
203         } while (!mnd.getImage().equals("bar"));
204 
205         List usages = (List) entry.getValue();
206         assertEquals(1, usages.size());
207         assertEquals("bar", ((JavaNameOccurrence) usages.get(0)).getImage());
208     }
209 
210     @Test
211     public void testMethodUsageSeenWithThis() {
212         parseCode(METHOD_USAGE_SEEN_WITH_THIS);
213         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
214         Map m = ((ClassScope) n.getScope()).getDeclarations();
215         Iterator i = m.entrySet().iterator();
216         MethodNameDeclaration mnd;
217         Map.Entry entry;
218         
219         do {
220             entry = (Map.Entry) i.next();
221             mnd = (MethodNameDeclaration) entry.getKey();
222         } while (!mnd.getImage().equals("bar"));
223 
224         List usages = (List) entry.getValue();
225         assertEquals(1, usages.size());
226         assertEquals("bar", ((JavaNameOccurrence) usages.get(0)).getImage());
227     }
228 
229     @Test
230     public void testMethodUsageSeen2() {
231         parseCode(METHOD_USAGE_SEEN2);
232         ASTClassOrInterfaceDeclaration n = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(0);
233 
234         Map<NameDeclaration, List<NameOccurrence>> m = ((ClassScope) n.getScope()).getDeclarations();
235 
236         assertEquals(2, m.size());
237 
238         for (Map.Entry<NameDeclaration, List<NameOccurrence>> entry : m.entrySet()) {
239             assertEquals("baz", entry.getKey().getImage());
240             if (entry.getKey().getNode().getBeginLine() == 2) {
241                 // this is the public method declaration - it is not used anywhere
242                 assertEquals(0, entry.getValue().size());
243             } else if (entry.getKey().getNode().getBeginLine() == 5) {
244                 // this is the private (overloaded) method 
245                 assertEquals(1, entry.getValue().size());
246                 // it's used once in line 3
247                 assertEquals(3, entry.getValue().get(0).getLocation().getBeginLine());
248             } else {
249                 fail("unexpected name declaration");
250             }
251         }
252     }
253 
254     /**
255      * Test case for bug report #2410201
256      */
257     @Test
258     public void testNestedClassFieldAndParameter() {
259     	parseCode(NESTED_CLASS_FIELD_AND_PARAM);
260     	ASTMethodDeclaration node = acu.getFirstDescendantOfType(ASTMethodDeclaration.class);
261     	Map<NameDeclaration, List<NameOccurrence>> vd = node.getScope().getDeclarations();
262     	assertEquals(1, vd.size());
263     	
264     	for (Map.Entry<NameDeclaration, List<NameOccurrence>> entry : vd.entrySet()) {
265     		assertEquals("field", entry.getKey().getImage());
266     		
267     		List<NameOccurrence> occurrences = entry.getValue();
268 			assertEquals(2, occurrences.size());
269 			NameOccurrence no1 = occurrences.get(0);
270 			assertEquals(8, no1.getLocation().getBeginLine());
271 			NameOccurrence no2 = occurrences.get(1);
272 			assertEquals(9, no2.getLocation().getBeginLine());
273     	}
274     	
275     }
276 
277     @Test
278     public void testNullType() {
279         parseCode(TEST_NULL_TYPE);
280     }
281 
282     private static final String NESTED_CLASS_FIELD_AND_PARAM =
283             "public class Foo {" + PMD.EOL +
284             " class Test {" + PMD.EOL +
285             "   public String field;" + PMD.EOL +
286             "   public Test t;" + PMD.EOL +
287             " }" + PMD.EOL +
288             " public void foo(String field) {" + PMD.EOL +
289             "   Test t = new Test();" + PMD.EOL +
290             "   t.field = field;" + PMD.EOL +
291             "   t.t.field = field;" + PMD.EOL +
292             " }" + PMD.EOL +
293             "}";
294 
295     private static final String METHOD_USAGE_SEEN2 =
296             "public class Foo {" + PMD.EOL +
297             " public void baz() {" + PMD.EOL +
298             "  baz(x, y);" + PMD.EOL +
299             " }" + PMD.EOL +
300             " private void baz(int x, int y) {}" + PMD.EOL +
301             "}";
302 
303 
304     private static final String METHOD_USAGE_SEEN =
305             "public class Foo {" + PMD.EOL +
306             " private void bar() {}" + PMD.EOL +
307             " public void buz() {" + PMD.EOL +
308             "  bar();" + PMD.EOL +
309             " }" + PMD.EOL +
310             "}";
311 
312     private static final String METHOD_USAGE_SEEN_WITH_THIS =
313             "public class Foo {" + PMD.EOL +
314             " private void bar() {}" + PMD.EOL +
315             " public void buz() {" + PMD.EOL +
316             "  this.bar();" + PMD.EOL +
317             " }" + PMD.EOL +
318             "}";
319 
320 
321     private static final String METH =
322             "public class Test {" + PMD.EOL +
323             "  static { " + PMD.EOL +
324             "   int y; " + PMD.EOL +
325             "  } " + PMD.EOL +
326             "  void bar(int x) {} " + PMD.EOL +
327             "  void baz(int x) {} " + PMD.EOL +
328             "}";
329 
330     private static final String NESTED_CLASS_FOUND =
331             "public class Test {" + PMD.EOL +
332             "  private class Buz {} " + PMD.EOL +
333             "}";
334 
335     private static final String ONE_PARAM =
336             "public class Test {" + PMD.EOL +
337             "  void bar(String x) {" + PMD.EOL +
338             "  }" + PMD.EOL +
339             "}";
340 
341     private static final String TWO_PARAMS =
342             "public class Test {" + PMD.EOL +
343             "  void bar(String x, int y) {" + PMD.EOL +
344             "  }" + PMD.EOL +
345             "}";
346 
347     private static final String NO_PARAMS =
348             "public class Test {" + PMD.EOL +
349             "  void bar() {" + PMD.EOL +
350             "  }" + PMD.EOL +
351             "}";
352 
353     private static final String ONE_PARAM_VARARG =
354             "public class Test {" + PMD.EOL +
355             "  void bar(String... s) {" + PMD.EOL +
356             "  }" + PMD.EOL +
357             "}";
358 
359     private static final String TWO_PARAMS_VARARG =
360             "public class Test {" + PMD.EOL +
361             "  void bar(String s1, String... s2) {" + PMD.EOL +
362             "  }" + PMD.EOL +
363             "}";
364 
365 
366     private static final String CLASS_NAME =
367             "public class Foo {}";
368 
369     private static final String METHOD_DECLARATIONS_RECORDED =
370             "public class Foo {" + PMD.EOL +
371             " private void bar() {}" + PMD.EOL +
372             "}";
373 
374     private static final String METHODS_WITH_DIFF_ARG =
375             "public class Foo {" + PMD.EOL +
376             " private void bar(String x) {}" + PMD.EOL +
377             " private void bar() {}" + PMD.EOL +
378             "}";
379 
380     private static final String ENUM_SCOPE =
381             "public enum Foo {" + PMD.EOL +
382             " HEAP(\"foo\");" + PMD.EOL +
383             " private final String fuz;" + PMD.EOL +
384             " public String getFuz() {" + PMD.EOL +
385             "  return fuz;" + PMD.EOL +
386             " }" + PMD.EOL +
387             "}";
388 
389     public static final String TEST_NULL_TYPE =
390             "public abstract class NullTypeTest {" + PMD.EOL +
391             "   protected Comparator<TreeNode> nodesComparator = (o1, o2) -> StringHelper.saveCompare(getFilterableString(o1), getFilterableString(o2));" + PMD.EOL +
392             "   public abstract String getFilterableString(TreeNode node);" + PMD.EOL +
393             "}";
394 
395     private static final String ENUM_TYPE_PARAMETER =
396             "public enum Foo {" + PMD.EOL +
397             "   BAR(isCustomer(BazEnum.FOO_BAR));" + PMD.EOL +
398             "   Foo(boolean isCustomer) { }" + PMD.EOL +
399             "   private static boolean isCustomer(BazEnum baz) {" + PMD.EOL +
400             "      return false;" + PMD.EOL +
401             "   }" + PMD.EOL +
402             "}";
403 
404     public static junit.framework.Test suite() {
405         return new junit.framework.JUnit4TestAdapter(ClassScopeTest.class);
406     }
407 }