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;
22
23import java.util.*;
24
25/**
26 * This class stores a specification of classes and possibly class members.
27 * The specification is template-based: the class names and class member names
28 * and descriptors can contain wildcards. Classes can be specified explicitly,
29 * or as extensions or implementations in the class hierarchy.
30 *
31 * @author Eric Lafortune
32 */
33public class ClassSpecification implements Cloneable
34{
35    public final String comments;
36    public       int    requiredSetAccessFlags;
37    public       int    requiredUnsetAccessFlags;
38    public final String annotationType;
39    public       String className;
40    public final String extendsAnnotationType;
41    public final String extendsClassName;
42
43    public       List   fieldSpecifications;
44    public       List   methodSpecifications;
45
46
47    /**
48     * Creates a new ClassSpecification for all possible classes, without
49     * comments or class members.
50     */
51    public ClassSpecification()
52    {
53        this(null,
54             0,
55             0,
56             null,
57             null,
58             null,
59             null);
60    }
61
62
63    /**
64     * Creates a new ClassSpecification that is a copy of the given specification.
65     */
66    public ClassSpecification(ClassSpecification classSpecification)
67    {
68        this(classSpecification.comments,
69             classSpecification.requiredSetAccessFlags,
70             classSpecification.requiredUnsetAccessFlags,
71             classSpecification.annotationType,
72             classSpecification.className,
73             classSpecification.extendsAnnotationType,
74             classSpecification.extendsClassName,
75             classSpecification.fieldSpecifications,
76             classSpecification.methodSpecifications);
77    }
78
79
80    /**
81     * Creates a new ClassSpecification for the specified class(es), without
82     * class members.
83     *
84     * @param comments                 provides optional comments on this
85     *                                 specification.
86     * @param requiredSetAccessFlags   the class access flags that must be set
87     *                                 in order for the class to apply.
88     * @param requiredUnsetAccessFlags the class access flags that must be
89     *                                 unset in order for the class to apply.
90     * @param annotationType           the name of the class that must be an
91     *                                 annotation of the class in order for it
92     *                                 to apply. The name may be null to
93     *                                 specify that no annotation is required.
94     * @param className                the class name. The name may be null to
95     *                                 specify any class, or it may contain
96     *                                 "**", "*", or "?" wildcards.
97     * @param extendsAnnotationType    the name of the class of that must be
98     *                                 an annotation of the class that the
99     *                                 class must extend or implement in order
100     *                                 to apply. The name may be null to
101     *                                 specify that no annotation is required.
102     * @param extendsClassName         the name of the class that the class
103     *                                 must extend or implement in order to
104     *                                 apply. The name may be null to specify
105     *                                 any class.
106     */
107    public ClassSpecification(String comments,
108                              int    requiredSetAccessFlags,
109                              int    requiredUnsetAccessFlags,
110                              String annotationType,
111                              String className,
112                              String extendsAnnotationType,
113                              String extendsClassName)
114    {
115        this(comments,
116             requiredSetAccessFlags,
117             requiredUnsetAccessFlags,
118             annotationType,
119             className,
120             extendsAnnotationType,
121             extendsClassName,
122             null,
123             null);
124    }
125
126
127    /**
128     * Creates a new ClassSpecification for the specified classes and class
129     * members.
130     *
131     * @param comments                 provides optional comments on this
132     *                                 specification.
133     * @param requiredSetAccessFlags   the class access flags that must be set
134     *                                 in order for the class to apply.
135     * @param requiredUnsetAccessFlags the class access flags that must be
136     *                                 unset in order for the class to apply.
137     * @param annotationType           the name of the class that must be an
138     *                                 annotation of the class in order for it
139     *                                 to apply. The name may be null to
140     *                                 specify that no annotation is required.
141     * @param className                the class name. The name may be null to
142     *                                 specify any class, or it may contain
143     *                                 "**", "*", or "?" wildcards.
144     * @param extendsAnnotationType    the name of the class of that must be
145     *                                 an annotation of the class that the
146     *                                 class must extend or implement in order
147     *                                 to apply. The name may be null to
148     *                                 specify that no annotation is required.
149     * @param extendsClassName         the name of the class that the class
150     *                                 must extend or implement in order to
151     *                                 apply. The name may be null to specify
152     *                                 any class.
153     * @param fieldSpecifications      the field specifications.
154     * @param methodSpecifications     the method specifications.
155     */
156    public ClassSpecification(String comments,
157                              int    requiredSetAccessFlags,
158                              int    requiredUnsetAccessFlags,
159                              String annotationType,
160                              String className,
161                              String extendsAnnotationType,
162                              String extendsClassName,
163                              List   fieldSpecifications,
164                              List   methodSpecifications)
165    {
166        this.comments                 = comments;
167        this.requiredSetAccessFlags   = requiredSetAccessFlags;
168        this.requiredUnsetAccessFlags = requiredUnsetAccessFlags;
169        this.annotationType           = annotationType;
170        this.className                = className;
171        this.extendsAnnotationType    = extendsAnnotationType;
172        this.extendsClassName         = extendsClassName;
173        this.fieldSpecifications      = fieldSpecifications;
174        this.methodSpecifications     = methodSpecifications;
175    }
176
177
178    /**
179     * Specifies to keep the specified field(s) of this option's class(es).
180     *
181     * @param fieldSpecification the field specification.
182     */
183    public void addField(MemberSpecification fieldSpecification)
184    {
185        if (fieldSpecifications == null)
186        {
187            fieldSpecifications = new ArrayList();
188        }
189
190        fieldSpecifications.add(fieldSpecification);
191    }
192
193
194    /**
195     * Specifies to keep the specified method(s) of this option's class(es).
196     *
197     * @param methodSpecification the method specification.
198     */
199    public void addMethod(MemberSpecification methodSpecification)
200    {
201        if (methodSpecifications == null)
202        {
203            methodSpecifications = new ArrayList();
204        }
205
206        methodSpecifications.add(methodSpecification);
207    }
208
209
210
211    // Implementations for Object.
212
213    public boolean equals(Object object)
214    {
215        if (object == null ||
216            this.getClass() != object.getClass())
217        {
218            return false;
219        }
220
221        ClassSpecification other = (ClassSpecification)object;
222        return
223//          (this.comments                 == null ? other.comments              == null : this.comments.equals(other.comments)                          ) &&
224            (this.requiredSetAccessFlags   == other.requiredSetAccessFlags                                                                               ) &&
225            (this.requiredUnsetAccessFlags == other.requiredUnsetAccessFlags                                                                             ) &&
226            (this.annotationType           == null ? other.annotationType        == null : this.annotationType.equals(other.annotationType)              ) &&
227            (this.className                == null ? other.className             == null : this.className.equals(other.className)                        ) &&
228            (this.extendsAnnotationType    == null ? other.extendsAnnotationType == null : this.extendsAnnotationType.equals(other.extendsAnnotationType)) &&
229            (this.extendsClassName         == null ? other.extendsClassName      == null : this.extendsClassName.equals(other.extendsClassName)          ) &&
230            (this.fieldSpecifications      == null ? other.fieldSpecifications   == null : this.fieldSpecifications.equals(other.fieldSpecifications)    ) &&
231            (this.methodSpecifications     == null ? other.methodSpecifications  == null : this.methodSpecifications.equals(other.methodSpecifications)  );
232    }
233
234    public int hashCode()
235    {
236        return
237//          (comments              == null ? 0 : comments.hashCode()             ) ^
238            (requiredSetAccessFlags                                              ) ^
239            (requiredUnsetAccessFlags                                            ) ^
240            (annotationType        == null ? 0 : annotationType.hashCode()       ) ^
241            (className             == null ? 0 : className.hashCode()            ) ^
242            (extendsAnnotationType == null ? 0 : extendsAnnotationType.hashCode()) ^
243            (extendsClassName      == null ? 0 : extendsClassName.hashCode()     ) ^
244            (fieldSpecifications   == null ? 0 : fieldSpecifications.hashCode()  ) ^
245            (methodSpecifications  == null ? 0 : methodSpecifications.hashCode() );
246    }
247
248    public Object clone()
249    {
250        try
251        {
252            return super.clone();
253        }
254        catch (CloneNotSupportedException e)
255        {
256            return null;
257        }
258    }
259}
260