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