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.ast.ASTName;
7 import net.sourceforge.pmd.ast.SimpleNode;
8 import net.sourceforge.pmd.util.Applier;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Map;
15
16 public class ClassScope extends AbstractScope {
17
18 protected Map classNames = new HashMap();
19 protected Map methodNames = new HashMap();
20 protected Map variableNames = new HashMap();
21
22
23 private static int anonymousInnerClassCounter = 1;
24 private String className;
25
26 public ClassScope(String className) {
27 this.className = className;
28 anonymousInnerClassCounter = 1;
29 }
30
31 /***
32 * This is only for anonymous inner classes
33 * <p/>
34 * FIXME - should have name like Foo$1, not Anonymous$1
35 * to get this working right, the parent scope needs
36 * to be passed in when instantiating a ClassScope
37 */
38 public ClassScope() {
39
40 this.className = "Anonymous$" + String.valueOf(anonymousInnerClassCounter);
41 anonymousInnerClassCounter++;
42 }
43
44 public void addDeclaration(VariableNameDeclaration variableDecl) {
45 if (variableNames.containsKey(variableDecl)) {
46 throw new RuntimeException(variableDecl + " is already in the symbol table");
47 }
48 variableNames.put(variableDecl, new ArrayList());
49 }
50
51 public NameDeclaration addVariableNameOccurrence(NameOccurrence occurrence) {
52 NameDeclaration decl = findVariableHere(occurrence);
53 if (decl != null && occurrence.isMethodOrConstructorInvocation()) {
54 List nameOccurrences = (List) methodNames.get(decl);
55 if (nameOccurrences == null) {
56
57 } else {
58 nameOccurrences.add(occurrence);
59 SimpleNode n = occurrence.getLocation();
60 if (n instanceof ASTName) {
61 ((ASTName) n).setNameDeclaration(decl);
62 }
63 }
64
65 } else if (decl != null && !occurrence.isThisOrSuper()) {
66 List nameOccurrences = (List) variableNames.get(decl);
67 if (nameOccurrences == null) {
68
69 } else {
70 nameOccurrences.add(occurrence);
71 SimpleNode n = occurrence.getLocation();
72 if (n instanceof ASTName) {
73 ((ASTName) n).setNameDeclaration(decl);
74 }
75 }
76 }
77 return decl;
78 }
79
80 public Map getVariableDeclarations() {
81 VariableUsageFinderFunction f = new VariableUsageFinderFunction(variableNames);
82 Applier.apply(f, variableNames.keySet().iterator());
83 return f.getUsed();
84 }
85
86 public Map getMethodDeclarations() {
87 return methodNames;
88 }
89
90 public Map getClassDeclarations() {
91 return classNames;
92 }
93
94 public ClassScope getEnclosingClassScope() {
95 return this;
96 }
97
98 public String getClassName() {
99 return this.className;
100 }
101
102 public void addDeclaration(MethodNameDeclaration decl) {
103 methodNames.put(decl, new ArrayList());
104 }
105
106 public void addDeclaration(ClassNameDeclaration decl) {
107 classNames.put(decl, new ArrayList());
108 }
109
110 protected NameDeclaration findVariableHere(NameOccurrence occurrence) {
111 if (occurrence.isThisOrSuper() || occurrence.getImage().equals(className)) {
112 if (variableNames.isEmpty() && methodNames.isEmpty()) {
113
114
115
116
117 return null;
118 }
119
120
121
122
123
124
125
126
127 if (!variableNames.isEmpty()) {
128 return (NameDeclaration) variableNames.keySet().iterator().next();
129 }
130 return (NameDeclaration) methodNames.keySet().iterator().next();
131 }
132
133 if (occurrence.isMethodOrConstructorInvocation()) {
134 for (Iterator i = methodNames.keySet().iterator(); i.hasNext();) {
135 MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
136 if (mnd.getImage().equals(occurrence.getImage())) {
137 int args = occurrence.getArgumentCount();
138 if (args == mnd.getParameterCount()) {
139
140
141
142
143 return mnd;
144 }
145 }
146 }
147 return null;
148 }
149
150 List images = new ArrayList();
151 images.add(occurrence.getImage());
152 if (occurrence.getImage().startsWith(className)) {
153 images.add(clipClassName(occurrence.getImage()));
154 }
155 ImageFinderFunction finder = new ImageFinderFunction(images);
156 Applier.apply(finder, variableNames.keySet().iterator());
157 return finder.getDecl();
158 }
159
160 public String toString() {
161 String res = "ClassScope (" + className + "): ";
162 if (!classNames.isEmpty()) res += "(" + glomNames(classNames.keySet().iterator()) + ")";
163 if (!methodNames.isEmpty()) {
164 Iterator i = methodNames.keySet().iterator();
165 while (i.hasNext()) {
166 MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
167 res += mnd.toString();
168 int usages = ((List) methodNames.get(mnd)).size();
169 res += "(begins at line " + mnd.getNode().getBeginLine() + ", " + usages + " usages)";
170 res += ",";
171 }
172 }
173 if (!variableNames.isEmpty()) res += "(" + glomNames(variableNames.keySet().iterator()) + ")";
174 return res;
175 }
176
177 private String clipClassName(String in) {
178 return in.substring(in.indexOf('.') + 1);
179 }
180 }