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