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.shrink;
22
23import proguard.classfile.*;
24import proguard.classfile.constant.*;
25import proguard.classfile.constant.visitor.ConstantVisitor;
26import proguard.classfile.util.SimplifiedVisitor;
27import proguard.classfile.visitor.ClassVisitor;
28
29
30/**
31 * This ClassVisitor recursively marks all interface
32 * classes that are being used in the visited class.
33 *
34 * @see UsageMarker
35 *
36 * @author Eric Lafortune
37 */
38public class InterfaceUsageMarker
39extends      SimplifiedVisitor
40implements   ClassVisitor,
41             ConstantVisitor
42{
43    private final UsageMarker usageMarker;
44
45    // Fields acting as a return parameters for several methods.
46    private boolean used;
47    private boolean anyUsed;
48
49
50    /**
51     * Creates a new InterfaceUsageMarker.
52     * @param usageMarker the usage marker that is used to mark the classes
53     *                    and class members.
54     */
55    public InterfaceUsageMarker(UsageMarker usageMarker)
56    {
57        this.usageMarker = usageMarker;
58    }
59
60
61    // Implementations for ClassVisitor.
62
63    public void visitProgramClass(ProgramClass programClass)
64    {
65        boolean classUsed         = usageMarker.isUsed(programClass);
66        boolean classPossiblyUsed = usageMarker.isPossiblyUsed(programClass);
67
68        if (classUsed || classPossiblyUsed)
69        {
70            // Check if any interfaces are being used.
71            boolean oldAnyUsed = anyUsed;
72            anyUsed = false;
73
74            programClass.interfaceConstantsAccept(this);
75
76            classUsed |= anyUsed;
77            anyUsed = oldAnyUsed;
78
79            // Is this an interface with a preliminary mark?
80            if (classPossiblyUsed)
81            {
82                // Should it be included now?
83                if (classUsed)
84                {
85                    // At least one if this interface's interfaces is being used.
86                    // Mark this interface as well.
87                    usageMarker.markAsUsed(programClass);
88
89                    // Mark this interface's name.
90                    programClass.thisClassConstantAccept(this);
91
92                    // Mark the superclass (java/lang/Object).
93                    programClass.superClassConstantAccept(this);
94                }
95                else
96                {
97                    // Unmark this interface, so we don't bother looking at it again.
98                    usageMarker.markAsUnused(programClass);
99                }
100            }
101        }
102
103        // The return value.
104        used = classUsed;
105    }
106
107
108    public void visitLibraryClass(LibraryClass libraryClass)
109    {
110        // The return values.
111        used    = true;
112        anyUsed = true;
113    }
114
115
116    // Implementations for ConstantVisitor.
117
118    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
119    {
120        boolean classUsed = usageMarker.isUsed(classConstant);
121
122        if (!classUsed)
123        {
124            // The ClassConstant isn't marked as being used yet. But maybe it
125            // should be included as an interface, so check the actual class.
126            classConstant.referencedClassAccept(this);
127            classUsed = used;
128
129            if (classUsed)
130            {
131                // The class is being used. Mark the ClassConstant as being used
132                // as well.
133                usageMarker.markAsUsed(classConstant);
134
135                clazz.constantPoolEntryAccept(classConstant.u2nameIndex, this);
136            }
137        }
138
139        // The return values.
140        used    =  classUsed;
141        anyUsed |= classUsed;
142    }
143
144
145    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
146    {
147        if (!usageMarker.isUsed(utf8Constant))
148        {
149            usageMarker.markAsUsed(utf8Constant);
150        }
151    }
152}
153