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 net.sourceforge.pmd.util.Applier;
7   
8   import java.util.ArrayList;
9   import java.util.HashMap;
10  import java.util.List;
11  import java.util.Map;
12  
13  public class ClassScope extends AbstractScope {
14  
15      protected Map methodNames = new HashMap();
16      protected Map variableNames = new HashMap();
17  
18      // FIXME - this breaks give sufficiently nested code
19      private static int anonymousInnerClassCounter = 1;
20      private String className;
21  
22      public ClassScope(String className) {
23          this.className = className;
24          anonymousInnerClassCounter = 1;
25      }
26  
27      /***
28       * This is only for anonymous inner classes
29       * <p/>
30       * FIXME - should have name like Foo$1, not Anonymous$1
31       * to get this working right, the parent scope needs
32       * to be passed in when instantiating a ClassScope
33       */
34      public ClassScope() {
35          //this.className = getParent().getEnclosingClassScope().getClassName() + "$" + String.valueOf(anonymousInnerClassCounter);
36          this.className = "Anonymous$" + String.valueOf(anonymousInnerClassCounter);
37          anonymousInnerClassCounter++;
38      }
39  
40      public void addDeclaration(VariableNameDeclaration variableDecl) {
41          if (variableNames.containsKey(variableDecl)) {
42              throw new RuntimeException("Variable " + variableDecl + " is already in the symbol table");
43          }
44          variableNames.put(variableDecl, new ArrayList());
45      }
46  
47      public NameDeclaration addVariableNameOccurrence(NameOccurrence occurrence) {
48          NameDeclaration decl = findVariableHere(occurrence);
49          if (decl != null && !occurrence.isThisOrSuper()) {
50              List nameOccurrences = (List) variableNames.get(decl);
51              nameOccurrences.add(occurrence);
52          }
53          return decl;
54      }
55  
56      public Map getVariableDeclarations() {
57          VariableUsageFinderFunction f = new VariableUsageFinderFunction(variableNames);
58          Applier.apply(f, variableNames.keySet().iterator());
59          return f.getUsed();
60      }
61  
62      public ClassScope getEnclosingClassScope() {
63          return this;
64      }
65  
66      public String getClassName() {
67          return this.className;
68      }
69  
70      public void addDeclaration(MethodNameDeclaration decl) {
71          methodNames.put(decl, new ArrayList());
72      }
73  
74      protected NameDeclaration findVariableHere(NameOccurrence occurrence) {
75          if (occurrence.isThisOrSuper() || occurrence.getImage().equals(className)) {
76              if (variableNames.isEmpty()) {
77                  // this could happen if you do this:
78                  // public class Foo {
79                  //  private String x = super.toString();
80                  // }
81                  return null;
82              }
83              // return any name declaration, since all we really want is to get the scope
84              // for example, if there's a
85              // public class Foo {
86              //  private static final int X = 2;
87              //  private int y = Foo.X;
88              // }
89              // we'll look up Foo just to get a handle to the class scope
90              // and then we'll look up X.
91              return (NameDeclaration) variableNames.keySet().iterator().next();
92          }
93  
94          List images = new ArrayList();
95          images.add(occurrence.getImage());
96          if (occurrence.getImage().startsWith(className)) {
97              images.add(clipClassName(occurrence.getImage()));
98          }
99          ImageFinderFunction finder = new ImageFinderFunction(images);
100         Applier.apply(finder, variableNames.keySet().iterator());
101         return finder.getDecl();
102     }
103 
104     public String toString() {
105         String res = "ClassScope:" + className + ":";
106         res += "\nmethods: " + super.glomNames(methodNames.keySet().iterator());
107         res += "\nvariables: " + super.glomNames(variableNames.keySet().iterator());
108         return res;
109     }
110 
111     private String clipClassName(String in) {
112         int firstDot = in.indexOf('.');
113         return in.substring(firstDot + 1);
114     }
115 }