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 } else {
72 nameOccurrences.add(occurrence);
73 Node n = occurrence.getLocation();
74 if (n instanceof ASTName) {
75 ((ASTName) n).setNameDeclaration(decl);
76 }
77 }
78 }
79 return decl;
80 }
81
82 public Map<VariableNameDeclaration, List<NameOccurrence>> getVariableDeclarations() {
83 VariableUsageFinderFunction f = new VariableUsageFinderFunction(variableNames);
84 Applier.apply(f, variableNames.keySet().iterator());
85 return f.getUsed();
86 }
87
88 public Map<MethodNameDeclaration, List<NameOccurrence>> getMethodDeclarations() {
89 return methodNames;
90 }
91
92 public Map<ClassNameDeclaration, List<NameOccurrence>> getClassDeclarations() {
93 return classNames;
94 }
95
96 public ClassScope getEnclosingClassScope() {
97 return this;
98 }
99
100 public String getClassName() {
101 return this.className;
102 }
103
104 public void addDeclaration(MethodNameDeclaration decl) {
105 methodNames.put(decl, new ArrayList<NameOccurrence>());
106 }
107
108 public void addDeclaration(ClassNameDeclaration decl) {
109 classNames.put(decl, new ArrayList<NameOccurrence>());
110 }
111
112 protected NameDeclaration findVariableHere(NameOccurrence occurrence) {
113 if (occurrence.isThisOrSuper() || occurrence.getImage().equals(className)) {
114 if (variableNames.isEmpty() && methodNames.isEmpty()) {
115
116
117
118
119 return null;
120 }
121
122
123
124
125
126
127
128
129 if (!variableNames.isEmpty()) {
130 return variableNames.keySet().iterator().next();
131 }
132 return methodNames.keySet().iterator().next();
133 }
134
135 if (occurrence.isMethodOrConstructorInvocation()) {
136 for (MethodNameDeclaration mnd: methodNames.keySet()) {
137 if (mnd.getImage().equals(occurrence.getImage())) {
138 int args = occurrence.getArgumentCount();
139 if (args == mnd.getParameterCount() || (mnd.isVarargs() && args >= mnd.getParameterCount() - 1)) {
140
141
142
143
144 return mnd;
145 }
146 }
147 }
148 return null;
149 }
150
151 List<String> images = new ArrayList<String>();
152 images.add(occurrence.getImage());
153 if (occurrence.getImage().startsWith(className)) {
154 images.add(clipClassName(occurrence.getImage()));
155 }
156 ImageFinderFunction finder = new ImageFinderFunction(images);
157 Applier.apply(finder, variableNames.keySet().iterator());
158 return finder.getDecl();
159 }
160
161 public String toString() {
162 String res = "ClassScope (" + className + "): ";
163 if (!classNames.isEmpty()) {
164 res += "(" + glomNames(classNames.keySet()) + ")";
165 }
166 if (!methodNames.isEmpty()) {
167 for (MethodNameDeclaration mnd: methodNames.keySet()) {
168 res += mnd.toString();
169 int usages = methodNames.get(mnd).size();
170 res += "(begins at line " + mnd.getNode().getBeginLine() + ", " + usages + " usages)";
171 res += ",";
172 }
173 }
174 if (!variableNames.isEmpty()) {
175 res += "(" + glomNames(variableNames.keySet()) + ")";
176 }
177 return res;
178 }
179
180 private String clipClassName(String s) {
181 return s.substring(s.indexOf('.') + 1);
182 }
183 }