1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.classfile;
22
23import proguard.classfile.attribute.visitor.AttributeVisitor;
24import proguard.classfile.constant.visitor.ConstantVisitor;
25import proguard.classfile.util.*;
26import proguard.classfile.visitor.*;
27
28/**
29 * This Clazz is a compact representation of the essential data in a Java class.
30 *
31 * @author Eric Lafortune
32 */
33public class LibraryClass implements Clazz
34{
35    public int             u2accessFlags;
36    public String          thisClassName;
37    public String          superClassName;
38    public String[]        interfaceNames;
39    public LibraryField[]  fields;
40    public LibraryMethod[] methods;
41
42    /**
43     * An extra field pointing to the superclass of this class.
44     * This field is filled out by the {@link ClassSuperHierarchyInitializer}.
45     */
46    public Clazz   superClass;
47
48    /**
49     * An extra field pointing to the interfaces of this class.
50     * This field is filled out by the {@link ClassSuperHierarchyInitializer}.
51     */
52    public Clazz[] interfaceClasses;
53
54    /**
55     * An extra field pointing to the subclasses of this class.
56     * This field is filled out by the {@link ClassSubHierarchyInitializer}.
57     */
58    public Clazz[] subClasses;
59
60    /**
61     * An extra field in which visitors can store information.
62     */
63    public Object visitorInfo;
64
65
66    /**
67     * Creates an empty LibraryClass.
68     */
69    public LibraryClass() {}
70
71
72    /**
73     * Returns whether this library class is visible to the outside world.
74     */
75    boolean isVisible()
76    {
77        return (u2accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0;
78    }
79
80
81    // Implementations for Clazz.
82
83    public int getAccessFlags()
84    {
85        return u2accessFlags;
86    }
87
88    public String getName()
89    {
90        return thisClassName;
91    }
92
93    public String getSuperName()
94    {
95        // This may be java/lang/Object, in which case there is no super.
96        return superClassName;
97    }
98
99    public int getInterfaceCount()
100    {
101        return interfaceClasses.length;
102    }
103
104    public String getInterfaceName(int index)
105    {
106        return interfaceNames[index];
107    }
108
109    public int getTag(int constantIndex)
110    {
111        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
112    }
113
114    public String getString(int constantIndex)
115    {
116        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
117    }
118
119    public String getStringString(int constantIndex)
120    {
121        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
122    }
123
124    public String getClassName(int constantIndex)
125    {
126        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
127    }
128
129    public String getName(int constantIndex)
130    {
131        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
132    }
133
134    public String getType(int constantIndex)
135    {
136        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
137    }
138
139
140    public void addSubClass(Clazz clazz)
141    {
142        if (subClasses == null)
143        {
144            subClasses = new Clazz[1];
145        }
146        else
147        {
148            // Copy the old elements into new larger array.
149            Clazz[] temp     = new Clazz[subClasses.length+1];
150            System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
151            subClasses = temp;
152        }
153
154        subClasses[subClasses.length-1] = clazz;
155    }
156
157
158    public Clazz getSuperClass()
159    {
160        return superClass;
161    }
162
163
164    public Clazz getInterface(int index)
165    {
166        return interfaceClasses[index];
167    }
168
169
170    public boolean extends_(Clazz clazz)
171    {
172        if (this.equals(clazz))
173        {
174            return true;
175        }
176
177        return superClass != null &&
178               superClass.extends_(clazz);
179    }
180
181
182    public boolean extendsOrImplements(Clazz clazz)
183    {
184        if (this.equals(clazz))
185        {
186            return true;
187        }
188
189        if (superClass != null &&
190            superClass.extendsOrImplements(clazz))
191        {
192            return true;
193        }
194
195        if (interfaceClasses != null)
196        {
197            for (int index = 0; index < interfaceClasses.length; index++)
198            {
199                Clazz interfaceClass = interfaceClasses[index];
200                if (interfaceClass != null &&
201                    interfaceClass.extendsOrImplements(clazz))
202                {
203                    return true;
204                }
205            }
206        }
207
208        return false;
209    }
210
211
212    public Field findField(String name, String descriptor)
213    {
214        for (int index = 0; index < fields.length; index++)
215        {
216            Field field = fields[index];
217            if (field != null &&
218                (name       == null || field.getName(this).equals(name)) &&
219                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
220            {
221                return field;
222            }
223        }
224
225        return null;
226    }
227
228
229    public Method findMethod(String name, String descriptor)
230    {
231        for (int index = 0; index < methods.length; index++)
232        {
233            Method method = methods[index];
234            if (method != null &&
235                (name       == null || method.getName(this).equals(name)) &&
236                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
237            {
238                return method;
239            }
240        }
241
242        return null;
243    }
244
245
246    public void accept(ClassVisitor classVisitor)
247    {
248        classVisitor.visitLibraryClass(this);
249    }
250
251
252    public void hierarchyAccept(boolean      visitThisClass,
253                                boolean      visitSuperClass,
254                                boolean      visitInterfaces,
255                                boolean      visitSubclasses,
256                                ClassVisitor classVisitor)
257    {
258        // First visit the current classfile.
259        if (visitThisClass)
260        {
261            accept(classVisitor);
262        }
263
264        // Then visit its superclass, recursively.
265        if (visitSuperClass)
266        {
267            if (superClass != null)
268            {
269                superClass.hierarchyAccept(true,
270                                           true,
271                                           visitInterfaces,
272                                           false,
273                                           classVisitor);
274            }
275        }
276
277        // Then visit its interfaces, recursively.
278        if (visitInterfaces)
279        {
280            // Visit the interfaces of the superclasses, if we haven't done so yet.
281            if (!visitSuperClass)
282            {
283                if (superClass != null)
284                {
285                    superClass.hierarchyAccept(false,
286                                               false,
287                                               true,
288                                               false,
289                                               classVisitor);
290                }
291            }
292
293            // Visit the interfaces.
294            if (interfaceClasses != null)
295            {
296                for (int index = 0; index < interfaceClasses.length; index++)
297                {
298                    Clazz interfaceClass = interfaceClasses[index];
299                    if (interfaceClass != null)
300                    {
301                        interfaceClass.hierarchyAccept(true,
302                                                       false,
303                                                       true,
304                                                       false,
305                                                       classVisitor);
306                    }
307                }
308            }
309        }
310
311        // Then visit its subclasses, recursively.
312        if (visitSubclasses)
313        {
314            if (subClasses != null)
315            {
316                for (int index = 0; index < subClasses.length; index++)
317                {
318                    subClasses[index].hierarchyAccept(true,
319                                                      false,
320                                                      false,
321                                                      true,
322                                                      classVisitor);
323                }
324            }
325        }
326    }
327
328
329    /**
330     * Lets the given class visitor visit the superclass, if it is known.
331     * @param classVisitor the <code>ClassVisitor</code> that will visit the
332     *                     superclass.
333     */
334    public void superClassAccept(ClassVisitor classVisitor)
335    {
336        if (superClass != null)
337        {
338            superClass.accept(classVisitor);
339        }
340    }
341
342
343    /**
344     * Lets the given class visitor visit all known direct interfaces.
345     * @param classVisitor the <code>ClassVisitor</code> that will visit the
346     *                     interfaces.
347     */
348    public void interfacesAccept(ClassVisitor classVisitor)
349    {
350        if (interfaceClasses != null)
351        {
352            for (int index = 0; index < interfaceClasses.length; index++)
353            {
354                Clazz interfaceClass = interfaceClasses[index];
355                if (interfaceClass != null)
356                {
357                    interfaceClass.accept(classVisitor);
358                }
359            }
360        }
361    }
362
363
364    public void subclassesAccept(ClassVisitor classVisitor)
365    {
366        if (subClasses != null)
367        {
368            for (int index = 0; index < subClasses.length; index++)
369            {
370                subClasses[index].accept(classVisitor);
371            }
372        }
373    }
374
375
376    public void constantPoolEntriesAccept(ConstantVisitor constantVisitor)
377    {
378        // This class doesn't keep references to its constant pool entries.
379    }
380
381
382    public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
383    {
384        // This class doesn't keep references to its constant pool entries.
385    }
386
387
388    public void thisClassConstantAccept(ConstantVisitor constantVisitor)
389    {
390        // This class doesn't keep references to its constant pool entries.
391    }
392
393
394    public void superClassConstantAccept(ConstantVisitor constantVisitor)
395    {
396        // This class doesn't keep references to its constant pool entries.
397    }
398
399
400    public void interfaceConstantsAccept(ConstantVisitor constantVisitor)
401    {
402        // This class doesn't keep references to its constant pool entries.
403    }
404
405
406    public void fieldsAccept(MemberVisitor memberVisitor)
407    {
408        for (int index = 0; index < fields.length; index++)
409        {
410            Field field = fields[index];
411            if (field != null)
412            {
413                field.accept(this, memberVisitor);
414            }
415        }
416    }
417
418
419    public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)
420    {
421        Field field = findField(name, descriptor);
422        if (field != null)
423        {
424            field.accept(this, memberVisitor);
425        }
426    }
427
428
429    public void methodsAccept(MemberVisitor memberVisitor)
430    {
431        for (int index = 0; index < methods.length; index++)
432        {
433            Method method = methods[index];
434            if (method != null)
435            {
436                method.accept(this, memberVisitor);
437            }
438        }
439    }
440
441
442    public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor)
443    {
444        Method method = findMethod(name, descriptor);
445        if (method != null)
446        {
447            method.accept(this, memberVisitor);
448        }
449    }
450
451
452    public boolean mayHaveImplementations(Method method)
453    {
454        return
455           (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
456           (method == null ||
457            ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
458                                         ClassConstants.INTERNAL_ACC_STATIC  |
459                                         ClassConstants.INTERNAL_ACC_FINAL)) == 0 &&
460                                                                                  !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)));
461    }
462
463
464    public void attributesAccept(AttributeVisitor attributeVisitor)
465    {
466        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
467    }
468
469
470    // Implementations for VisitorAccepter.
471
472    public Object getVisitorInfo()
473    {
474        return visitorInfo;
475    }
476
477    public void setVisitorInfo(Object visitorInfo)
478    {
479        this.visitorInfo = visitorInfo;
480    }
481
482
483    // Implementations for Object.
484
485    public String toString()
486    {
487        return "LibraryClass("+getName()+")";
488    }
489}
490