1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 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 String getRefName(int constantIndex)
141    {
142        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
143    }
144
145    public String getRefType(int constantIndex)
146    {
147        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
148    }
149
150
151    public void addSubClass(Clazz clazz)
152    {
153        if (subClasses == null)
154        {
155            subClasses = new Clazz[1];
156        }
157        else
158        {
159            // Copy the old elements into new larger array.
160            Clazz[] temp     = new Clazz[subClasses.length+1];
161            System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
162            subClasses = temp;
163        }
164
165        subClasses[subClasses.length-1] = clazz;
166    }
167
168
169    public Clazz getSuperClass()
170    {
171        return superClass;
172    }
173
174
175    public Clazz getInterface(int index)
176    {
177        return interfaceClasses[index];
178    }
179
180
181    public boolean extends_(Clazz clazz)
182    {
183        if (this.equals(clazz))
184        {
185            return true;
186        }
187
188        return superClass != null &&
189               superClass.extends_(clazz);
190    }
191
192
193    public boolean extends_(String className)
194    {
195        if (getName().equals(className))
196        {
197            return true;
198        }
199
200        return superClass != null &&
201               superClass.extends_(className);
202    }
203
204
205    public boolean extendsOrImplements(Clazz clazz)
206    {
207        if (this.equals(clazz))
208        {
209            return true;
210        }
211
212        if (superClass != null &&
213            superClass.extendsOrImplements(clazz))
214        {
215            return true;
216        }
217
218        if (interfaceClasses != null)
219        {
220            for (int index = 0; index < interfaceClasses.length; index++)
221            {
222                Clazz interfaceClass = interfaceClasses[index];
223                if (interfaceClass != null &&
224                    interfaceClass.extendsOrImplements(clazz))
225                {
226                    return true;
227                }
228            }
229        }
230
231        return false;
232    }
233
234
235    public boolean extendsOrImplements(String className)
236    {
237        if (getName().equals(className))
238        {
239            return true;
240        }
241
242        if (superClass != null &&
243            superClass.extendsOrImplements(className))
244        {
245            return true;
246        }
247
248        if (interfaceClasses != null)
249        {
250            for (int index = 0; index < interfaceClasses.length; index++)
251            {
252                Clazz interfaceClass = interfaceClasses[index];
253                if (interfaceClass != null &&
254                    interfaceClass.extendsOrImplements(className))
255                {
256                    return true;
257                }
258            }
259        }
260
261        return false;
262    }
263
264
265    public Field findField(String name, String descriptor)
266    {
267        for (int index = 0; index < fields.length; index++)
268        {
269            Field field = fields[index];
270            if (field != null &&
271                (name       == null || field.getName(this).equals(name)) &&
272                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
273            {
274                return field;
275            }
276        }
277
278        return null;
279    }
280
281
282    public Method findMethod(String name, String descriptor)
283    {
284        for (int index = 0; index < methods.length; index++)
285        {
286            Method method = methods[index];
287            if (method != null &&
288                (name       == null || method.getName(this).equals(name)) &&
289                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
290            {
291                return method;
292            }
293        }
294
295        return null;
296    }
297
298
299    public void accept(ClassVisitor classVisitor)
300    {
301        classVisitor.visitLibraryClass(this);
302    }
303
304
305    public void hierarchyAccept(boolean      visitThisClass,
306                                boolean      visitSuperClass,
307                                boolean      visitInterfaces,
308                                boolean      visitSubclasses,
309                                ClassVisitor classVisitor)
310    {
311        // First visit the current classfile.
312        if (visitThisClass)
313        {
314            accept(classVisitor);
315        }
316
317        // Then visit its superclass, recursively.
318        if (visitSuperClass)
319        {
320            if (superClass != null)
321            {
322                superClass.hierarchyAccept(true,
323                                           true,
324                                           visitInterfaces,
325                                           false,
326                                           classVisitor);
327            }
328        }
329
330        // Then visit its interfaces, recursively.
331        if (visitInterfaces)
332        {
333            // Visit the interfaces of the superclasses, if we haven't done so yet.
334            if (!visitSuperClass)
335            {
336                if (superClass != null)
337                {
338                    superClass.hierarchyAccept(false,
339                                               false,
340                                               true,
341                                               false,
342                                               classVisitor);
343                }
344            }
345
346            // Visit the interfaces.
347            if (interfaceClasses != null)
348            {
349                for (int index = 0; index < interfaceClasses.length; index++)
350                {
351                    Clazz interfaceClass = interfaceClasses[index];
352                    if (interfaceClass != null)
353                    {
354                        interfaceClass.hierarchyAccept(true,
355                                                       false,
356                                                       true,
357                                                       false,
358                                                       classVisitor);
359                    }
360                }
361            }
362        }
363
364        // Then visit its subclasses, recursively.
365        if (visitSubclasses)
366        {
367            if (subClasses != null)
368            {
369                for (int index = 0; index < subClasses.length; index++)
370                {
371                    subClasses[index].hierarchyAccept(true,
372                                                      false,
373                                                      false,
374                                                      true,
375                                                      classVisitor);
376                }
377            }
378        }
379    }
380
381
382    /**
383     * Lets the given class visitor visit the superclass, if it is known.
384     * @param classVisitor the <code>ClassVisitor</code> that will visit the
385     *                     superclass.
386     */
387    public void superClassAccept(ClassVisitor classVisitor)
388    {
389        if (superClass != null)
390        {
391            superClass.accept(classVisitor);
392        }
393    }
394
395
396    /**
397     * Lets the given class visitor visit all known direct interfaces.
398     * @param classVisitor the <code>ClassVisitor</code> that will visit the
399     *                     interfaces.
400     */
401    public void interfacesAccept(ClassVisitor classVisitor)
402    {
403        if (interfaceClasses != null)
404        {
405            for (int index = 0; index < interfaceClasses.length; index++)
406            {
407                Clazz interfaceClass = interfaceClasses[index];
408                if (interfaceClass != null)
409                {
410                    interfaceClass.accept(classVisitor);
411                }
412            }
413        }
414    }
415
416
417    public void subclassesAccept(ClassVisitor classVisitor)
418    {
419        if (subClasses != null)
420        {
421            for (int index = 0; index < subClasses.length; index++)
422            {
423                subClasses[index].accept(classVisitor);
424            }
425        }
426    }
427
428
429    public void constantPoolEntriesAccept(ConstantVisitor constantVisitor)
430    {
431        // This class doesn't keep references to its constant pool entries.
432    }
433
434
435    public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
436    {
437        // This class doesn't keep references to its constant pool entries.
438    }
439
440
441    public void thisClassConstantAccept(ConstantVisitor constantVisitor)
442    {
443        // This class doesn't keep references to its constant pool entries.
444    }
445
446
447    public void superClassConstantAccept(ConstantVisitor constantVisitor)
448    {
449        // This class doesn't keep references to its constant pool entries.
450    }
451
452
453    public void interfaceConstantsAccept(ConstantVisitor constantVisitor)
454    {
455        // This class doesn't keep references to its constant pool entries.
456    }
457
458
459    public void fieldsAccept(MemberVisitor memberVisitor)
460    {
461        for (int index = 0; index < fields.length; index++)
462        {
463            Field field = fields[index];
464            if (field != null)
465            {
466                field.accept(this, memberVisitor);
467            }
468        }
469    }
470
471
472    public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)
473    {
474        Field field = findField(name, descriptor);
475        if (field != null)
476        {
477            field.accept(this, memberVisitor);
478        }
479    }
480
481
482    public void methodsAccept(MemberVisitor memberVisitor)
483    {
484        for (int index = 0; index < methods.length; index++)
485        {
486            Method method = methods[index];
487            if (method != null)
488            {
489                method.accept(this, memberVisitor);
490            }
491        }
492    }
493
494
495    public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor)
496    {
497        Method method = findMethod(name, descriptor);
498        if (method != null)
499        {
500            method.accept(this, memberVisitor);
501        }
502    }
503
504
505    public boolean mayHaveImplementations(Method method)
506    {
507        return
508           (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
509           (method == null ||
510            ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
511                                         ClassConstants.INTERNAL_ACC_STATIC  |
512                                         ClassConstants.INTERNAL_ACC_FINAL)) == 0 &&
513                                                                                  !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)));
514    }
515
516
517    public void attributesAccept(AttributeVisitor attributeVisitor)
518    {
519        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
520    }
521
522
523    public void attributeAccept(String name, AttributeVisitor attributeVisitor)
524    {
525        throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
526    }
527
528
529    // Implementations for VisitorAccepter.
530
531    public Object getVisitorInfo()
532    {
533        return visitorInfo;
534    }
535
536    public void setVisitorInfo(Object visitorInfo)
537    {
538        this.visitorInfo = visitorInfo;
539    }
540
541
542    // Implementations for Object.
543
544    public String toString()
545    {
546        return "LibraryClass("+getName()+")";
547    }
548}
549