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.shrink;
22
23import proguard.classfile.*;
24import proguard.classfile.visitor.*;
25
26
27/**
28 * This class can be used as a mark when keeping classes, class members, and
29 * other elements. It can be certain or preliminary. It also contains additional
30 * information about the reasons why an element is being kept.
31 *
32 * @see ClassShrinker
33 *
34 * @author Eric Lafortune
35 */
36final class ShortestUsageMark
37{
38    private final boolean certain;
39    private final String  reason;
40    private final int     depth;
41    private       Clazz   clazz;
42    private       Member  member;
43
44
45    /**
46     * Creates a new certain ShortestUsageMark.
47     * @param reason the reason for this mark.
48     */
49    public ShortestUsageMark(String reason)
50    {
51        this.certain = true;
52        this.reason  = reason;
53        this.depth   = 0;
54    }
55
56
57    /**
58     * Creates a new certain ShortestUsageMark.
59     * @param previousUsageMark the previous mark to which this one is linked.
60     * @param reason            the reason for this mark.
61     * @param clazz             the class causing this mark.
62     */
63    public ShortestUsageMark(ShortestUsageMark previousUsageMark,
64                             String            reason,
65                             int               cost,
66                             Clazz             clazz)
67    {
68        this(previousUsageMark, reason, cost, clazz, null);
69    }
70
71
72    /**
73     * Creates a new certain ShortestUsageMark.
74     * @param previousUsageMark the previous mark to which this one is linked.
75     * @param reason            the reason for this mark.
76     * @param clazz             the class causing this mark.
77     * @param member            the member in the above class causing this mark.
78     * @param cost              the added cost of following this path.
79     */
80    public ShortestUsageMark(ShortestUsageMark previousUsageMark,
81                             String            reason,
82                             int               cost,
83                             Clazz             clazz,
84                             Member            member)
85    {
86        this.certain = true;
87        this.reason  = reason;
88        this.depth   = previousUsageMark.depth + cost;
89        this.clazz   = clazz;
90        this.member  = member;
91    }
92
93
94    /**
95     * Creates a new ShortestUsageMark, based on another mark.
96     * @param otherUsageMark the other mark, whose properties will be copied.
97     * @param certain        specifies whether this is a certain mark.
98     */
99    public ShortestUsageMark(ShortestUsageMark otherUsageMark,
100                             boolean           certain)
101    {
102        this.certain = certain;
103        this.reason  = otherUsageMark.reason;
104        this.depth   = otherUsageMark.depth;
105        this.clazz   = otherUsageMark.clazz;
106        this.member  = otherUsageMark.member;
107    }
108
109
110    /**
111     * Returns whether this is a certain mark.
112     */
113    public boolean isCertain()
114    {
115        return certain;
116    }
117
118
119    /**
120     * Returns the reason for this mark.
121     */
122    public String getReason()
123    {
124        return reason;
125    }
126
127
128    /**
129     * Returns whether this mark has a shorter chain of reasons than the
130     * given mark.
131     */
132    public boolean isShorter(ShortestUsageMark otherUsageMark)
133    {
134        return this.depth < otherUsageMark.depth;
135    }
136
137
138    /**
139     * Returns whether this is mark is caused by the given class.
140     */
141    public boolean isCausedBy(Clazz clazz)
142    {
143        return clazz.equals(this.clazz);
144    }
145
146
147    /**
148     * Applies the given class visitor to this mark's class, if any,
149     * and if this mark doesn't have a member.
150     */
151    public void acceptClassVisitor(ClassVisitor classVisitor)
152    {
153        if (clazz  != null &&
154            member == null)
155        {
156            clazz.accept(classVisitor);
157        }
158    }
159
160
161    /**
162     * Applies the given class visitor to this mark's member, if any.
163     */
164    public void acceptMemberVisitor(MemberVisitor memberVisitor)
165    {
166        if (clazz  != null &&
167            member != null)
168        {
169            member.accept(clazz, memberVisitor);
170        }
171    }
172
173
174    // Implementations for Object.
175
176    public String toString()
177    {
178        return "certain=" + certain + ", depth="+depth+": " +
179               reason +
180               (clazz      != null ? clazz.getName() : "(none)") + ": " +
181               (member     != null ? member.getName(clazz) : "(none)");
182    }
183}
184