1
2
3
4 package net.sourceforge.pmd.lang.java.symboltable;
5
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import net.sourceforge.pmd.lang.ast.Node;
12 import net.sourceforge.pmd.lang.java.ast.ASTName;
13
14 public class ClassScope extends AbstractScope {
15
16 protected Map<ClassNameDeclaration, List<NameOccurrence>> classNames = new HashMap<ClassNameDeclaration, List<NameOccurrence>>();
17 protected Map<MethodNameDeclaration, List<NameOccurrence>> methodNames = new HashMap<MethodNameDeclaration, List<NameOccurrence>>();
18 protected Map<VariableNameDeclaration, List<NameOccurrence>> variableNames = new HashMap<VariableNameDeclaration, List<NameOccurrence>>();
19
20
21 private static ThreadLocal<Integer> anonymousInnerClassCounter = new ThreadLocal<Integer>() {
22 protected Integer initialValue() { return Integer.valueOf(1); }
23 };
24
25 private String className;
26
27 public ClassScope(String className) {
28 this.className = className;
29 anonymousInnerClassCounter.set(Integer.valueOf(1));
30 }
31
32
33
34
35
36
37
38
39 public ClassScope() {
40
41 int v = anonymousInnerClassCounter.get().intValue();
42 this.className = "Anonymous$" + v;
43 anonymousInnerClassCounter.set(v + 1);
44 }
45
46 public void addDeclaration(VariableNameDeclaration variableDecl) {
47 if (variableNames.containsKey(variableDecl)) {
48 throw new RuntimeException(variableDecl + " is already in the symbol table");
49 }
50 variableNames.put(variableDecl, new ArrayList<NameOccurrence>());
51 }
52
53 public NameDeclaration addVariableNameOccurrence(NameOccurrence occurrence) {
54 NameDeclaration decl = findVariableHere(occurrence);
55 if (decl != null && occurrence.isMethodOrConstructorInvocation()) {
56 List<NameOccurrence> nameOccurrences = methodNames.get(decl);
57 if (nameOccurrences == null) {
58
59 } else {
60 nameOccurrences.add(occurrence);
61 Node n = occurrence.getLocation();
62 if (n instanceof ASTName) {
63 ((ASTName) n).setNameDeclaration(decl);
64 }
65 }
66
67 } else if (decl != null && !occurrence.isThisOrSuper()) {
68 List<NameOccurrence> nameOccurrences = variableNames.get(decl);
69 if (nameOccurrences == null) {
70
71
72
73 for (ClassNameDeclaration innerClass : classNames.keySet()) {
74 Scope innerClassScope = innerClass.getScope();
75 if (innerClassScope.contains(occurrence)) {
76 innerClassScope.addVariableNameOccurrence(occurrence);
77 }
78 }
79 } else {
80 nameOccurrences.add(occurrence);
81 Node n = occurrence.getLocation();
82 if (n instanceof ASTName) {
83 ((ASTName) n).setNameDeclaration(decl);
84 }
85 }
86 }
87 return decl;
88 }
89
90 public Map<VariableNameDeclaration, List<NameOccurrence>> getVariableDeclarations() {
91 VariableUsageFinderFunction f = new VariableUsageFinderFunction(variableNames);
92 Applier.apply(f, variableNames.keySet().iterator());
93 return f.getUsed();
94 }
95
96 public Map<MethodNameDeclaration, List<NameOccurrence>> getMethodDeclarations() {
97 return methodNames;
98 }
99
100 public Map<ClassNameDeclaration, List<NameOccurrence>> getClassDeclarations() {
101 return classNames;
102 }
103
104 public ClassScope getEnclosingClassScope() {
105 return this;
106 }
107
108 public String getClassName() {
109 return this.className;
110 }
111
112 public void addDeclaration(MethodNameDeclaration decl) {
113 methodNames.put(decl, new ArrayList<NameOccurrence>());
114 }
115
116 public void addDeclaration(ClassNameDeclaration decl) {
117 classNames.put(decl, new ArrayList<NameOccurrence>());
118 }
119
120 protected NameDeclaration findVariableHere(NameOccurrence occurrence) {
121 if (occurrence.isThisOrSuper() || occurrence.getImage().equals(className)) {
122 if (variableNames.isEmpty() && methodNames.isEmpty()) {
123
124
125
126
127 return null;
128 }
129
130
131
132
133
134
135
136
137 if (!variableNames.isEmpty()) {
138 return variableNames.keySet().iterator().next();
139 }
140 return methodNames.keySet().iterator().next();
141 }
142
143 if (occurrence.isMethodOrConstructorInvocation()) {
144 for (MethodNameDeclaration mnd: methodNames.keySet()) {
145 if (mnd.getImage().equals(occurrence.getImage())) {
146 int args = occurrence.getArgumentCount();
147 if (args == mnd.getParameterCount() || (mnd.isVarargs() && args >= mnd.getParameterCount() - 1)) {
148
149
150
151
152 return mnd;
153 }
154 }
155 }
156 return null;
157 }
158
159 List<String> images = new ArrayList<String>();
160 images.add(occurrence.getImage());
161 if (occurrence.getImage().startsWith(className)) {
162 images.add(clipClassName(occurrence.getImage()));
163 }
164 ImageFinderFunction finder = new ImageFinderFunction(images);
165 Applier.apply(finder, variableNames.keySet().iterator());
166 NameDeclaration result = finder.getDecl();
167
168
169 if (result == null && !classNames.isEmpty()) {
170 for (ClassNameDeclaration innerClass : classNames.keySet()) {
171 Applier.apply(finder, innerClass.getScope().getVariableDeclarations().keySet().iterator());
172 result = finder.getDecl();
173 if (result != null) {
174 break;
175 }
176 }
177 }
178 return result;
179 }
180
181 public String toString() {
182 StringBuilder res = new StringBuilder("ClassScope (").append(className).append("): ");
183 if (!classNames.isEmpty()) {
184 res.append("Inner Classes ").append(glomNames(classNames.keySet())).append("; ");
185 }
186 if (!methodNames.isEmpty()) {
187 for (MethodNameDeclaration mnd: methodNames.keySet()) {
188 res.append(mnd.toString());
189 int usages = methodNames.get(mnd).size();
190 res.append("(begins at line ").append(mnd.getNode().getBeginLine()).append(", ").append(usages).append(" usages)");
191 res.append(", ");
192 }
193 }
194 if (!variableNames.isEmpty()) {
195 res.append("Variables ").append(glomNames(variableNames.keySet()));
196 }
197 return res.toString();
198 }
199
200 private String clipClassName(String s) {
201 return s.substring(s.indexOf('.') + 1);
202 }
203 }