001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This library is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This library is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
015: * for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this library; if not, write to the Free Software Foundation,
019: * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.classfile;
022:
023: import proguard.classfile.attribute.visitor.AttributeVisitor;
024: import proguard.classfile.constant.visitor.ConstantVisitor;
025: import proguard.classfile.util.*;
026: import proguard.classfile.visitor.*;
027:
028: /**
029: * This Clazz is a compact representation of the essential data in a Java class.
030: *
031: * @author Eric Lafortune
032: */
033: public class LibraryClass implements Clazz {
034: public int u2accessFlags;
035: public String this ClassName;
036: public String super ClassName;
037: public String[] interfaceNames;
038: public LibraryField[] fields;
039: public LibraryMethod[] methods;
040:
041: /**
042: * An extra field pointing to the superclass of this class.
043: * This field is filled out by the {@link ClassSuperHierarchyInitializer}.
044: */
045: public Clazz super Class;
046:
047: /**
048: * An extra field pointing to the interfaces of this class.
049: * This field is filled out by the {@link ClassSuperHierarchyInitializer}.
050: */
051: public Clazz[] interfaceClasses;
052:
053: /**
054: * An extra field pointing to the subclasses of this class.
055: * This field is filled out by the {@link ClassSubHierarchyInitializer}.
056: */
057: public Clazz[] subClasses;
058:
059: /**
060: * An extra field in which visitors can store information.
061: */
062: public Object visitorInfo;
063:
064: /**
065: * Creates an empty LibraryClass.
066: */
067: public LibraryClass() {
068: }
069:
070: /**
071: * Returns whether this library class is visible to the outside world.
072: */
073: boolean isVisible() {
074: return (u2accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0;
075: }
076:
077: // Implementations for Clazz.
078:
079: public int getAccessFlags() {
080: return u2accessFlags;
081: }
082:
083: public String getName() {
084: return this ClassName;
085: }
086:
087: public String getSuperName() {
088: // This may be java/lang/Object, in which case there is no super.
089: return super ClassName;
090: }
091:
092: public int getInterfaceCount() {
093: return interfaceClasses.length;
094: }
095:
096: public String getInterfaceName(int index) {
097: return interfaceNames[index];
098: }
099:
100: public int getTag(int constantIndex) {
101: throw new UnsupportedOperationException("Library class ["
102: + this ClassName + "] doesn't store constant pool");
103: }
104:
105: public String getString(int constantIndex) {
106: throw new UnsupportedOperationException("Library class ["
107: + this ClassName + "] doesn't store constant pool");
108: }
109:
110: public String getStringString(int constantIndex) {
111: throw new UnsupportedOperationException("Library class ["
112: + this ClassName + "] doesn't store constant pool");
113: }
114:
115: public String getClassName(int constantIndex) {
116: throw new UnsupportedOperationException("Library class ["
117: + this ClassName + "] doesn't store constant pool");
118: }
119:
120: public String getName(int constantIndex) {
121: throw new UnsupportedOperationException("Library class ["
122: + this ClassName + "] doesn't store constant pool");
123: }
124:
125: public String getType(int constantIndex) {
126: throw new UnsupportedOperationException("Library class ["
127: + this ClassName + "] doesn't store constant pool");
128: }
129:
130: public void addSubClass(Clazz clazz) {
131: if (subClasses == null) {
132: subClasses = new Clazz[1];
133: } else {
134: // Copy the old elements into new larger array.
135: Clazz[] temp = new Clazz[subClasses.length + 1];
136: System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
137: subClasses = temp;
138: }
139:
140: subClasses[subClasses.length - 1] = clazz;
141: }
142:
143: public Clazz getSuperClass() {
144: return super Class;
145: }
146:
147: public Clazz getInterface(int index) {
148: return interfaceClasses[index];
149: }
150:
151: public boolean extends_(Clazz clazz) {
152: if (this .equals(clazz)) {
153: return true;
154: }
155:
156: return super Class != null && super Class.extends_(clazz);
157: }
158:
159: public boolean extendsOrImplements(Clazz clazz) {
160: if (this .equals(clazz)) {
161: return true;
162: }
163:
164: if (super Class != null && super Class.extendsOrImplements(clazz)) {
165: return true;
166: }
167:
168: if (interfaceClasses != null) {
169: for (int index = 0; index < interfaceClasses.length; index++) {
170: Clazz interfaceClass = interfaceClasses[index];
171: if (interfaceClass != null
172: && interfaceClass.extendsOrImplements(clazz)) {
173: return true;
174: }
175: }
176: }
177:
178: return false;
179: }
180:
181: public Field findField(String name, String descriptor) {
182: for (int index = 0; index < fields.length; index++) {
183: Field field = fields[index];
184: if (field != null
185: && (name == null || field.getName(this )
186: .equals(name))
187: && (descriptor == null || field.getDescriptor(this )
188: .equals(descriptor))) {
189: return field;
190: }
191: }
192:
193: return null;
194: }
195:
196: public Method findMethod(String name, String descriptor) {
197: for (int index = 0; index < methods.length; index++) {
198: Method method = methods[index];
199: if (method != null
200: && (name == null || method.getName(this ).equals(
201: name))
202: && (descriptor == null || method
203: .getDescriptor(this ).equals(descriptor))) {
204: return method;
205: }
206: }
207:
208: return null;
209: }
210:
211: public void accept(ClassVisitor classVisitor) {
212: classVisitor.visitLibraryClass(this );
213: }
214:
215: public void hierarchyAccept(boolean visitThisClass,
216: boolean visitSuperClass, boolean visitInterfaces,
217: boolean visitSubclasses, ClassVisitor classVisitor) {
218: // First visit the current classfile.
219: if (visitThisClass) {
220: accept(classVisitor);
221: }
222:
223: // Then visit its superclass, recursively.
224: if (visitSuperClass) {
225: if (super Class != null) {
226: super Class.hierarchyAccept(true, true, visitInterfaces,
227: false, classVisitor);
228: }
229: }
230:
231: // Then visit its interfaces, recursively.
232: if (visitInterfaces) {
233: if (interfaceClasses != null) {
234: for (int index = 0; index < interfaceClasses.length; index++) {
235: Clazz interfaceClass = interfaceClasses[index];
236: if (interfaceClass != null) {
237: interfaceClass.hierarchyAccept(true, true,
238: true, false, classVisitor);
239: }
240: }
241: }
242: }
243:
244: // Then visit its subclasses, recursively.
245: if (visitSubclasses) {
246: if (subClasses != null) {
247: for (int index = 0; index < subClasses.length; index++) {
248: subClasses[index].hierarchyAccept(true, false,
249: false, true, classVisitor);
250: }
251: }
252: }
253: }
254:
255: public void constantPoolEntriesAccept(
256: ConstantVisitor constantVisitor) {
257: // This class doesn't keep references to its constant pool entries.
258: }
259:
260: public void constantPoolEntryAccept(int index,
261: ConstantVisitor constantVisitor) {
262: // This class doesn't keep references to its constant pool entries.
263: }
264:
265: public void fieldsAccept(MemberVisitor memberVisitor) {
266: for (int index = 0; index < fields.length; index++) {
267: Field field = fields[index];
268: if (field != null) {
269: field.accept(this , memberVisitor);
270: }
271: }
272: }
273:
274: public void fieldAccept(String name, String descriptor,
275: MemberVisitor memberVisitor) {
276: Field field = findField(name, descriptor);
277: if (field != null) {
278: field.accept(this , memberVisitor);
279: }
280: }
281:
282: public void methodsAccept(MemberVisitor memberVisitor) {
283: for (int index = 0; index < methods.length; index++) {
284: Method method = methods[index];
285: if (method != null) {
286: method.accept(this , memberVisitor);
287: }
288: }
289: }
290:
291: public void methodAccept(String name, String descriptor,
292: MemberVisitor memberVisitor) {
293: Method method = findMethod(name, descriptor);
294: if (method != null) {
295: method.accept(this , memberVisitor);
296: }
297: }
298:
299: public boolean mayHaveImplementations(Method method) {
300: return (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0
301: && (method == null || ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE
302: | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_FINAL)) == 0 && !method
303: .getName(this )
304: .equals(
305: ClassConstants.INTERNAL_METHOD_NAME_INIT)));
306: }
307:
308: private boolean isSpecial(Method method) {
309: return (method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC)) != 0
310: || method.getName(this ).equals(
311: ClassConstants.INTERNAL_METHOD_NAME_INIT);
312: }
313:
314: public void methodImplementationsAccept(Method method,
315: boolean visitThisMethod, MemberVisitor memberVisitor) {
316: methodImplementationsAccept(method.getName(this ), method
317: .getDescriptor(this ), method, visitThisMethod, true,
318: true, true, memberVisitor);
319: }
320:
321: public void methodImplementationsAccept(String name,
322: String descriptor, boolean visitThisMethod,
323: MemberVisitor memberVisitor) {
324: methodImplementationsAccept(name, descriptor, visitThisMethod,
325: true, true, true, memberVisitor);
326: }
327:
328: public void methodImplementationsAccept(String name,
329: String descriptor, boolean visitThisMethod,
330: boolean visitSpecialMethods, boolean visitSuperMethods,
331: boolean visitOverridingMethods, MemberVisitor memberVisitor) {
332: methodImplementationsAccept(name, descriptor, findMethod(name,
333: descriptor), visitThisMethod, visitSpecialMethods,
334: visitSuperMethods, visitOverridingMethods,
335: memberVisitor);
336: }
337:
338: public void methodImplementationsAccept(String name,
339: String descriptor, Method method, boolean visitThisMethod,
340: boolean visitSpecialMethods, boolean visitSuperMethods,
341: boolean visitOverridingMethods, MemberVisitor memberVisitor) {
342: // Do we have the method in this class?
343: if (method != null) {
344: // Is it a special method?
345: if (isSpecial(method)) {
346: // Visit the special method in this class, if allowed.
347: if (visitSpecialMethods) {
348: method.accept(this , memberVisitor);
349:
350: // The method can't have any other implementations.
351: return;
352: }
353: } else {
354: // Visit the method in this class, if allowed.
355: if (visitThisMethod) {
356: method.accept(this , memberVisitor);
357: }
358:
359: // We don't have to look in subclasses if there can't be
360: // any overriding implementations.
361: if (!mayHaveImplementations(method)) {
362: visitOverridingMethods = false;
363: }
364:
365: // We don't have to look in superclasses if we have a concrete
366: // implementation here.
367: if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) == 0) {
368: visitSuperMethods = false;
369: }
370: }
371: }
372:
373: // Then visit the method in its subclasses, recursively.
374: if (visitOverridingMethods) {
375: // Go looking for implementations in all of the subclasses.
376: if (subClasses != null) {
377: for (int index = 0; index < subClasses.length; index++) {
378: Clazz subClass = subClasses[index];
379: subClass.methodImplementationsAccept(name,
380: descriptor, true, false, visitSuperMethods,
381: true, memberVisitor);
382: }
383: }
384:
385: // We don't have to look in superclasses right away if we dont't
386: // have a concrete class here.
387: if ((u2accessFlags & (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0) {
388: visitSuperMethods = false;
389: }
390: }
391:
392: // Then visit the method in its superclass, recursively.
393: if (visitSuperMethods) {
394: if (super Class != null) {
395: super Class.methodImplementationsAccept(name,
396: descriptor, true, false, true, false,
397: memberVisitor);
398: }
399: }
400: }
401:
402: public void attributesAccept(AttributeVisitor attributeVisitor) {
403: throw new UnsupportedOperationException("Library class ["
404: + this ClassName + "] doesn't store attributes");
405: }
406:
407: // Implementations for VisitorAccepter.
408:
409: public Object getVisitorInfo() {
410: return visitorInfo;
411: }
412:
413: public void setVisitorInfo(Object visitorInfo) {
414: this.visitorInfo = visitorInfo;
415: }
416: }
|