Source code: com/puppycrawl/tools/checkstyle/checks/usage/transmogrify/ClassDef.java
1
2 // Transmogrify License
3 //
4 // Copyright (c) 2001, ThoughtWorks, Inc.
5 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 // - Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // - Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // Neither the name of the ThoughtWorks, Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from this
16 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 package com.puppycrawl.tools.checkstyle.checks.usage.transmogrify;
30
31 import java.util.ArrayList;
32 import java.util.Enumeration;
33 import java.util.HashSet;
34 import java.util.Hashtable;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Set;
38 import java.util.SortedSet;
39 import java.util.TreeSet;
40 import java.util.Vector;
41
42 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
43
44
45
46 /**
47 * <code>ClassDef</code> contains all the information needed to
48 * represent a java class or interface. This includes the superclass,
49 * whether it's a class or an interface, the interfaces it implements,
50 * a list of its (direct?) subclasses, and the classes that implement
51 * it if it is an interface
52 *
53 * @see Scope
54 */
55 public class ClassDef extends DefaultScope implements IClass {
56 private long id = 0;
57
58 private IClass superclass = null;
59 private List interfaces = new Vector();
60
61 private List subclasses = new Vector();
62 private List implementors = new Vector();
63
64 private Set importedPackages = new HashSet();
65
66 // variable definitions will use elements from parent
67 private Set methods = new HashSet();
68
69 private Hashtable imports = new Hashtable();
70 private Vector unprocessedImports = null;
71
72 protected MethodDef _defaultConstructor;
73
74 public ClassDef(String name, Scope parentScope, SymTabAST node) {
75 super(name, parentScope, node);
76 _defaultConstructor = new DefaultConstructor(this);
77 addDefinition(_defaultConstructor);
78 }
79
80 public long getNextAnonymousId() {
81 return ++id;
82 }
83
84 public void setSuperclass(IClass superclass) {
85 this.superclass = superclass;
86 }
87
88 public IClass getSuperclass() {
89 return superclass;
90 }
91
92 public void addUnprocessedImports(Vector imports) {
93 unprocessedImports = (Vector) (imports.clone());
94 }
95
96 public Vector getUnprocessedImports() {
97 return unprocessedImports;
98 }
99
100 public void importPackage(IPackage pkg) {
101 importedPackages.add(pkg);
102 }
103
104 public void importClass(IClass imported) {
105 imports.put(imported.getName(), imported);
106 }
107
108 // begin definitions interface
109
110 public void addDefinition(MethodDef method) {
111 if (method.getName().equals(getName())) {
112 methods.remove(_defaultConstructor);
113 }
114 methods.add(method);
115 }
116
117 protected Enumeration getDefinitions() {
118 Vector allElements = new Vector();
119
120 allElements.addAll(elements.values());
121 allElements.addAll(methods);
122 allElements.addAll(labels.values());
123 allElements.addAll(classes.values());
124
125 return allElements.elements();
126 }
127
128 public IClass getClassDefinition(String name) {
129 IClass result = null;
130
131 result = (ClassDef) (classes.get(name));
132
133 if (result == null) {
134 result = (IClass) (imports.get(name));
135 }
136
137 if (result == null) {
138 Iterator it = importedPackages.iterator();
139 while (it.hasNext() && result == null) {
140 IPackage pkg = (IPackage) it.next();
141 result = pkg.getClass(name);
142 }
143 }
144
145 if (result == null) {
146 result = getParentScope().getClassDefinition(name);
147 }
148
149 //TODO: check for a class in the same package?
150 if (result == null) {
151 final String packageName = getParentScope().getQualifiedName();
152 final String fullName = packageName + "." + name;
153 Class theClass = null;
154 try {
155 theClass = ClassManager.getClassLoader().loadClass(fullName);
156 result = new ExternalClass(theClass);
157 }
158 catch (ClassNotFoundException e) {
159 // no-op
160 }
161 }
162
163 return result;
164 }
165
166 public IMethod getMethodDefinition(String name, ISignature signature) {
167 IMethod result = null;
168
169 result = getDeclaredMethod(name, signature);
170
171 if (result == null) {
172 result = getMostCompatibleMethod(name, signature);
173 }
174
175 if (result == null) {
176 if (superclass != null) {
177 result = superclass.getMethodDefinition(name, signature);
178 }
179 }
180
181 if (result == null) {
182 IClass[] interfaces = getInterfaces();
183 for (int index = 0;
184 index < interfaces.length && result == null;
185 index++) {
186 result = interfaces[index].getMethodDefinition(name, signature);
187 }
188 }
189
190 // not sure why this is here -- inner classes, maybe?
191 // regardless, write better
192 if (result == null) {
193 if (getParentScope() != null) {
194 result = getParentScope().getMethodDefinition(name, signature);
195 }
196 }
197
198 return result;
199 }
200
201 public IMethod getMostCompatibleMethod(String name, ISignature signature) {
202 IMethod result = null;
203
204 SortedSet compatibleMethods =
205 new TreeSet(new MethodSpecificityComparator());
206
207 Iterator it = methods.iterator();
208 while (it.hasNext()) {
209 MethodDef method = (MethodDef) it.next();
210 if (name.equals(method.getName())) {
211 if (method.hasCompatibleSignature(signature)) {
212 compatibleMethods.add(method);
213 }
214 }
215 }
216
217 if (!compatibleMethods.isEmpty()) {
218 result = (IMethod) compatibleMethods.first();
219 }
220
221 return result;
222 }
223
224 public IMethod getDeclaredMethod(String name, ISignature signature) {
225 // finds methods declared by this class with the given signature
226
227 IMethod result = null;
228
229 Iterator it = methods.iterator();
230 while (it.hasNext()) {
231 MethodDef method = (MethodDef) it.next();
232 if (name.equals(method.getName())) {
233 if (method.hasSameSignature(signature)) {
234 result = method;
235 break;
236 }
237 }
238 }
239
240 return result;
241 }
242
243 public IVariable getVariableDefinition(String name) {
244 IVariable result = null;
245
246 // in keeping with getField in java.lang.Class
247 // 1) current class
248 // 2) direct superinterfaces
249 // 3) superclass
250 // then we do the parent scope in case its an inner class
251
252 result = (VariableDef) (elements.get(name));
253
254 if (result == null) {
255 IClass[] superinterfaces = getInterfaces();
256 for (int i = 0;
257 i < superinterfaces.length && result == null;
258 i++) {
259 result = superinterfaces[i].getVariableDefinition(name);
260 }
261 }
262
263 if (result == null) {
264 if (superclass != null) {
265 result = superclass.getVariableDefinition(name);
266 }
267 }
268
269 if (result == null) {
270 if (getParentScope() != null) {
271 result = getParentScope().getVariableDefinition(name);
272 }
273 }
274
275 return result;
276 }
277
278 // end definitions interface
279
280 public void addInterface(IClass implemented) {
281 interfaces.add(implemented);
282 }
283
284 public IClass[] getInterfaces() {
285 IClass[] type = new IClass[0];
286 return (IClass[]) interfaces.toArray(type);
287 }
288
289 public ClassDef getEnclosingClass() {
290 return this;
291 }
292
293 public void addSubclass(ClassDef subclass) {
294 subclasses.add(subclass);
295 }
296
297 public List getSubclasses() {
298 return subclasses;
299 }
300
301 public void addImplementor(ClassDef implementor) {
302 implementors.add(implementor);
303 }
304
305 public List getImplementors() {
306 return implementors;
307 }
308
309 public IClass[] getInnerClasses() {
310 Iterator it = getClasses();
311 List result = new ArrayList();
312
313 while (it.hasNext()) {
314 result.add(it.next());
315 }
316
317 return (IClass[]) result.toArray(new IClass[0]);
318 }
319
320 public boolean isSuperclassOf(IClass possibleChild) {
321 // justify my existence
322 boolean result = subclasses.contains(possibleChild);
323
324 /*
325 Iterator it = subclasses.iterator();
326 while (it.hasNext() && !result) {
327 IClass child = (IClass)it.next();
328 result = child.isSuperclassOf(possibleChild);
329 }
330 */
331 return result;
332 }
333
334 public boolean isCompatibleWith(IClass type) {
335 boolean result = false;
336
337 // check myself
338 if (type.equals(this)) {
339 result = true;
340 }
341 // check my superclass
342 else if (superclass != null && superclass.isCompatibleWith(type)) {
343 result = true;
344 }
345 // check my interfaces
346 else if (!interfaces.isEmpty()) {
347 Iterator it = interfaces.iterator();
348
349 while (it.hasNext() && !result) {
350 IClass current = (IClass) it.next();
351
352 if (current.isCompatibleWith(type)) {
353 result = true;
354 }
355 }
356 }
357
358 return result;
359 }
360
361 public boolean isPrimitive() {
362 return false;
363 }
364
365 private SymTabAST getObjblock() {
366 return getTreeNode().findFirstToken(TokenTypes.OBJBLOCK);
367 }
368
369 }