ProgramClass.java revision db267bc191f906f55eaef21a27110cce2ec57fdf
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.Attribute;
24import proguard.classfile.attribute.visitor.AttributeVisitor;
25import proguard.classfile.constant.*;
26import proguard.classfile.constant.visitor.ConstantVisitor;
27import proguard.classfile.util.ClassSubHierarchyInitializer;
28import proguard.classfile.visitor.*;
29
30/**
31 * This Clazz is a complete representation of the data in a Java class.
32 *
33 * @author Eric Lafortune
34 */
35public class ProgramClass implements Clazz
36{
37    public int             u4magic;
38    public int             u4version;
39    public int             u2constantPoolCount;
40    public Constant[]      constantPool;
41    public int             u2accessFlags;
42    public int             u2thisClass;
43    public int             u2superClass;
44    public int             u2interfacesCount;
45    public int[]           u2interfaces;
46    public int             u2fieldsCount;
47    public ProgramField[]  fields;
48    public int             u2methodsCount;
49    public ProgramMethod[] methods;
50    public int             u2attributesCount;
51    public Attribute[]     attributes;
52
53    /**
54     * An extra field pointing to the subclasses of this class.
55     * This field is filled out by the {@link ClassSubHierarchyInitializer}.
56     */
57    public Clazz[] subClasses;
58
59    /**
60     * An extra field in which visitors can store information.
61     */
62    public Object visitorInfo;
63
64
65    /**
66     * Creates an uninitialized ProgramClass.
67     */
68    public ProgramClass() {}
69
70
71    /**
72     * Returns the Constant at the given index in the constant pool.
73     */
74    public Constant getConstant(int constantIndex)
75    {
76        return constantPool[constantIndex];
77    }
78
79
80    // Implementations for Clazz.
81
82    public int getAccessFlags()
83    {
84        return u2accessFlags;
85    }
86
87    public String getName()
88    {
89        return getClassName(u2thisClass);
90    }
91
92    public String getSuperName()
93    {
94        return u2superClass == 0 ? null : getClassName(u2superClass);
95    }
96
97    public int getInterfaceCount()
98    {
99        return u2interfacesCount;
100    }
101
102    public String getInterfaceName(int index)
103    {
104        return getClassName(u2interfaces[index]);
105    }
106
107    public int getTag(int constantIndex)
108    {
109        return constantPool[constantIndex].getTag();
110    }
111
112    public String getString(int constantIndex)
113    {
114        try
115        {
116            return ((Utf8Constant)constantPool[constantIndex]).getString();
117        }
118        catch (ClassCastException ex)
119        {
120            new ClassPrinter().visitProgramClass(this);
121            throw new ClassCastException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
122        }
123    }
124
125    public String getStringString(int constantIndex)
126    {
127        try
128        {
129            return ((StringConstant)constantPool[constantIndex]).getString(this);
130        }
131        catch (ClassCastException ex)
132        {
133            throw new ClassCastException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
134        }
135    }
136
137    public String getClassName(int constantIndex)
138    {
139        try
140        {
141            return ((ClassConstant)constantPool[constantIndex]).getName(this);
142        }
143        catch (ClassCastException ex)
144        {
145            throw new ClassCastException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
146        }
147    }
148
149    public String getName(int constantIndex)
150    {
151        try
152        {
153            return ((NameAndTypeConstant)constantPool[constantIndex]).getName(this);
154        }
155        catch (ClassCastException ex)
156        {
157            throw new ClassCastException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
158        }
159    }
160
161    public String getType(int constantIndex)
162    {
163        try
164        {
165            return ((NameAndTypeConstant)constantPool[constantIndex]).getType(this);
166        }
167        catch (ClassCastException ex)
168        {
169            throw new ClassCastException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
170        }
171    }
172
173
174    public void addSubClass(Clazz clazz)
175    {
176        if (subClasses == null)
177        {
178            subClasses = new Clazz[1];
179        }
180        else
181        {
182            // Copy the old elements into new larger array.
183            Clazz[] temp = new Clazz[subClasses.length+1];
184            System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
185            subClasses = temp;
186        }
187
188        subClasses[subClasses.length-1] = clazz;
189    }
190
191
192    public Clazz getSuperClass()
193    {
194        return u2superClass != 0 ?
195            ((ClassConstant)constantPool[u2superClass]).referencedClass :
196            null;
197    }
198
199
200    public Clazz getInterface(int index)
201    {
202        return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass;
203    }
204
205
206    public boolean extends_(Clazz clazz)
207    {
208        if (this.equals(clazz))
209        {
210            return true;
211        }
212
213        Clazz superClass = getSuperClass();
214        return superClass != null &&
215               superClass.extends_(clazz);
216    }
217
218
219    public boolean extendsOrImplements(Clazz clazz)
220    {
221        if (this.equals(clazz))
222        {
223            return true;
224        }
225
226        Clazz superClass = getSuperClass();
227        if (superClass != null &&
228            superClass.extendsOrImplements(clazz))
229        {
230            return true;
231        }
232
233        for (int index = 0; index < u2interfacesCount; index++)
234        {
235            Clazz interfaceClass = getInterface(index);
236            if (interfaceClass != null &&
237                interfaceClass.extendsOrImplements(clazz))
238            {
239                return true;
240            }
241        }
242
243        return false;
244    }
245
246
247    public Field findField(String name, String descriptor)
248    {
249        for (int index = 0; index < u2fieldsCount; index++)
250        {
251            Field field = fields[index];
252            if ((name       == null || field.getName(this).equals(name)) &&
253                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
254            {
255                return field;
256            }
257        }
258
259        return null;
260    }
261
262
263    public Method findMethod(String name, String descriptor)
264    {
265        for (int index = 0; index < u2methodsCount; index++)
266        {
267            Method method = methods[index];
268            if ((name       == null || method.getName(this).equals(name)) &&
269                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
270            {
271                return method;
272            }
273        }
274
275        return null;
276    }
277
278
279    public void accept(ClassVisitor classVisitor)
280    {
281        classVisitor.visitProgramClass(this);
282    }
283
284
285    public void hierarchyAccept(boolean      visitThisClass,
286                                boolean      visitSuperClass,
287                                boolean      visitInterfaces,
288                                boolean      visitSubclasses,
289                                ClassVisitor classVisitor)
290    {
291        // First visit the current classfile.
292        if (visitThisClass)
293        {
294            accept(classVisitor);
295        }
296
297        // Then visit its superclass, recursively.
298        if (visitSuperClass)
299        {
300            Clazz superClass = getSuperClass();
301            if (superClass != null)
302            {
303                superClass.hierarchyAccept(true,
304                                           true,
305                                           visitInterfaces,
306                                           false,
307                                           classVisitor);
308            }
309        }
310
311        // Then visit its interfaces, recursively.
312        if (visitInterfaces)
313        {
314            // Visit the interfaces of the superclasses, if we haven't done so yet.
315            if (!visitSuperClass)
316            {
317                Clazz superClass = getSuperClass();
318                if (superClass != null)
319                {
320                    superClass.hierarchyAccept(false,
321                                               false,
322                                               true,
323                                               false,
324                                               classVisitor);
325                }
326            }
327
328            // Visit the interfaces.
329            for (int index = 0; index < u2interfacesCount; index++)
330            {
331                Clazz interfaceClass = getInterface(index);
332                if (interfaceClass != null)
333                {
334                    interfaceClass.hierarchyAccept(true,
335                                                   false,
336                                                   true,
337                                                   false,
338                                                   classVisitor);
339                }
340            }
341        }
342
343        // Then visit its subclasses, recursively.
344        if (visitSubclasses)
345        {
346            if (subClasses != null)
347            {
348                for (int index = 0; index < subClasses.length; index++)
349                {
350                    Clazz subClass = subClasses[index];
351                    subClass.hierarchyAccept(true,
352                                             false,
353                                             false,
354                                             true,
355                                             classVisitor);
356                }
357            }
358        }
359    }
360
361
362    public void subclassesAccept(ClassVisitor classVisitor)
363    {
364        if (subClasses != null)
365        {
366            for (int index = 0; index < subClasses.length; index++)
367            {
368                subClasses[index].accept(classVisitor);
369            }
370        }
371    }
372
373
374    public void constantPoolEntriesAccept(ConstantVisitor constantVisitor)
375    {
376        for (int index = 1; index < u2constantPoolCount; index++)
377        {
378            if (constantPool[index] != null)
379            {
380                constantPool[index].accept(this, constantVisitor);
381            }
382        }
383    }
384
385
386    public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
387    {
388        constantPool[index].accept(this, constantVisitor);
389    }
390
391
392    public void thisClassConstantAccept(ConstantVisitor constantVisitor)
393    {
394        constantPool[u2thisClass].accept(this, constantVisitor);
395    }
396
397
398    public void superClassConstantAccept(ConstantVisitor constantVisitor)
399    {
400        if (u2superClass != 0)
401        {
402            constantPool[u2superClass].accept(this, constantVisitor);
403        }
404    }
405
406
407    public void interfaceConstantsAccept(ConstantVisitor constantVisitor)
408    {
409        for (int index = 0; index < u2interfacesCount; index++)
410        {
411            constantPool[u2interfaces[index]].accept(this, constantVisitor);
412        }
413    }
414
415
416    public void fieldsAccept(MemberVisitor memberVisitor)
417    {
418        for (int index = 0; index < u2fieldsCount; index++)
419        {
420            fields[index].accept(this, memberVisitor);
421        }
422    }
423
424
425    public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)
426    {
427        Field field = findField(name, descriptor);
428        if (field != null)
429        {
430            field.accept(this, memberVisitor);
431        }
432    }
433
434
435    public void methodsAccept(MemberVisitor memberVisitor)
436    {
437        for (int index = 0; index < u2methodsCount; index++)
438        {
439            methods[index].accept(this, memberVisitor);
440        }
441    }
442
443
444    public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor)
445    {
446        Method method = findMethod(name, descriptor);
447        if (method != null)
448        {
449            method.accept(this, memberVisitor);
450        }
451    }
452
453
454    public boolean mayHaveImplementations(Method method)
455    {
456        return
457            (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
458            (method == null ||
459             ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
460                                          ClassConstants.INTERNAL_ACC_STATIC  |
461                                          ClassConstants.INTERNAL_ACC_FINAL)) == 0 &&
462              !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)));
463    }
464
465
466    public void attributesAccept(AttributeVisitor attributeVisitor)
467    {
468        for (int index = 0; index < u2attributesCount; index++)
469        {
470            attributes[index].accept(this, attributeVisitor);
471        }
472    }
473
474
475    // Implementations for VisitorAccepter.
476
477    public Object getVisitorInfo()
478    {
479        return visitorInfo;
480    }
481
482    public void setVisitorInfo(Object visitorInfo)
483    {
484        this.visitorInfo = visitorInfo;
485    }
486
487
488    // Implementations for Object.
489
490    public String toString()
491    {
492        return "ProgramClass("+getName()+")";
493    }
494}
495