1 |
| |
2 |
| |
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 |
1176
| public ClassScope(String className) {
|
27 |
1176
| this.className = className;
|
28 |
1176
| anonymousInnerClassCounter = 1;
|
29 |
| } |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
18
| public ClassScope() {
|
39 |
| |
40 |
18
| this.className = "Anonymous$" + String.valueOf(anonymousInnerClassCounter);
|
41 |
18
| anonymousInnerClassCounter++;
|
42 |
| } |
43 |
| |
44 |
357
| public void addDeclaration(VariableNameDeclaration variableDecl) {
|
45 |
357
| if (variableNames.containsKey(variableDecl)) {
|
46 |
0
| throw new RuntimeException(variableDecl + " is already in the symbol table");
|
47 |
| } |
48 |
357
| variableNames.put(variableDecl, new ArrayList());
|
49 |
| } |
50 |
| |
51 |
263
| public NameDeclaration addVariableNameOccurrence(NameOccurrence occurrence) {
|
52 |
263
| NameDeclaration decl = findVariableHere(occurrence);
|
53 |
263
| if (decl != null && occurrence.isMethodOrConstructorInvocation()) {
|
54 |
79
| List nameOccurrences = (List) methodNames.get(decl);
|
55 |
79
| if (nameOccurrences == null) {
|
56 |
| |
57 |
| } else { |
58 |
79
| nameOccurrences.add(occurrence);
|
59 |
79
| SimpleNode n = occurrence.getLocation();
|
60 |
79
| if (n instanceof ASTName) {
|
61 |
57
| ((ASTName) n).setNameDeclaration(decl);
|
62 |
| } |
63 |
| } |
64 |
| |
65 |
184
| } else if (decl != null && !occurrence.isThisOrSuper()) {
|
66 |
130
| List nameOccurrences = (List) variableNames.get(decl);
|
67 |
130
| if (nameOccurrences == null) {
|
68 |
| |
69 |
| } else { |
70 |
130
| nameOccurrences.add(occurrence);
|
71 |
130
| SimpleNode n = occurrence.getLocation();
|
72 |
130
| if (n instanceof ASTName) {
|
73 |
111
| ((ASTName) n).setNameDeclaration(decl);
|
74 |
| } |
75 |
| } |
76 |
| } |
77 |
263
| return decl;
|
78 |
| } |
79 |
| |
80 |
66
| public Map getVariableDeclarations() {
|
81 |
66
| VariableUsageFinderFunction f = new VariableUsageFinderFunction(variableNames);
|
82 |
66
| Applier.apply(f, variableNames.keySet().iterator());
|
83 |
66
| return f.getUsed();
|
84 |
| } |
85 |
| |
86 |
38
| public Map getMethodDeclarations() {
|
87 |
38
| return methodNames;
|
88 |
| } |
89 |
| |
90 |
1
| public Map getClassDeclarations() {
|
91 |
1
| return classNames;
|
92 |
| } |
93 |
| |
94 |
2258
| public ClassScope getEnclosingClassScope() {
|
95 |
2258
| return this;
|
96 |
| } |
97 |
| |
98 |
914
| public String getClassName() {
|
99 |
914
| return this.className;
|
100 |
| } |
101 |
| |
102 |
935
| public void addDeclaration(MethodNameDeclaration decl) {
|
103 |
935
| methodNames.put(decl, new ArrayList());
|
104 |
| } |
105 |
| |
106 |
59
| public void addDeclaration(ClassNameDeclaration decl) {
|
107 |
59
| classNames.put(decl, new ArrayList());
|
108 |
| } |
109 |
| |
110 |
1623
| protected NameDeclaration findVariableHere(NameOccurrence occurrence) {
|
111 |
1623
| if (occurrence.isThisOrSuper() || occurrence.getImage().equals(className)) {
|
112 |
183
| if (variableNames.isEmpty() && methodNames.isEmpty()) {
|
113 |
| |
114 |
| |
115 |
| |
116 |
| |
117 |
0
| return null;
|
118 |
| } |
119 |
| |
120 |
| |
121 |
| |
122 |
| |
123 |
| |
124 |
| |
125 |
| |
126 |
| |
127 |
183
| if (!variableNames.isEmpty()) {
|
128 |
84
| return (NameDeclaration) variableNames.keySet().iterator().next();
|
129 |
| } |
130 |
99
| return (NameDeclaration) methodNames.keySet().iterator().next();
|
131 |
| } |
132 |
| |
133 |
1440
| if (occurrence.isMethodOrConstructorInvocation()) {
|
134 |
789
| for (Iterator i = methodNames.keySet().iterator(); i.hasNext();) {
|
135 |
819
| MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
|
136 |
819
| if (mnd.getImage().equals(occurrence.getImage())) {
|
137 |
246
| int args = occurrence.getArgumentCount();
|
138 |
246
| if (args == mnd.getParameterCount()) {
|
139 |
| |
140 |
| |
141 |
| |
142 |
| |
143 |
237
| return mnd;
|
144 |
| } |
145 |
| } |
146 |
| } |
147 |
552
| return null;
|
148 |
| } |
149 |
| |
150 |
651
| List images = new ArrayList();
|
151 |
651
| images.add(occurrence.getImage());
|
152 |
651
| if (occurrence.getImage().startsWith(className)) {
|
153 |
1
| images.add(clipClassName(occurrence.getImage()));
|
154 |
| } |
155 |
651
| ImageFinderFunction finder = new ImageFinderFunction(images);
|
156 |
651
| Applier.apply(finder, variableNames.keySet().iterator());
|
157 |
651
| return finder.getDecl();
|
158 |
| } |
159 |
| |
160 |
0
| public String toString() {
|
161 |
0
| String res = "ClassScope (" + className + "): ";
|
162 |
0
| if (!classNames.isEmpty()) res += "(" + glomNames(classNames.keySet().iterator()) + ")";
|
163 |
0
| if (!methodNames.isEmpty()) {
|
164 |
0
| Iterator i = methodNames.keySet().iterator();
|
165 |
0
| while (i.hasNext()) {
|
166 |
0
| MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
|
167 |
0
| res += mnd.toString();
|
168 |
0
| int usages = ((List) methodNames.get(mnd)).size();
|
169 |
0
| res += "(begins at line " + mnd.getNode().getBeginLine() + ", " + usages + " usages)";
|
170 |
0
| res += ",";
|
171 |
| } |
172 |
| } |
173 |
0
| if (!variableNames.isEmpty()) res += "(" + glomNames(variableNames.keySet().iterator()) + ")";
|
174 |
0
| return res;
|
175 |
| } |
176 |
| |
177 |
1
| private String clipClassName(String in) {
|
178 |
1
| return in.substring(in.indexOf('.') + 1);
|
179 |
| } |
180 |
| } |