View Javadoc

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