• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package proguard.ant;
22 
23 import org.apache.tools.ant.BuildException;
24 import org.apache.tools.ant.types.DataType;
25 import proguard.MemberSpecification;
26 import proguard.classfile.*;
27 import proguard.classfile.util.ClassUtil;
28 import proguard.util.ListUtil;
29 
30 import java.util.*;
31 
32 /**
33  * This DataType represents a class member specification in Ant.
34  *
35  * @author Eric Lafortune
36  */
37 public class MemberSpecificationElement extends DataType
38 {
39     private String access;
40     private String annotation;
41     private String type;
42     private String name;
43     private String parameters;
44 
45 
46     /**
47      * Adds the contents of this class member specification element to the given
48      * list.
49      * @param memberSpecifications the class member specifications to be
50      *                                  extended.
51      * @param isMethod                  specifies whether this specification
52      *                                  refers to a method.
53      * @param isConstructor             specifies whether this specification
54      *                                  refers to a constructor.
55      */
appendTo(List memberSpecifications, boolean isMethod, boolean isConstructor)56     public void appendTo(List    memberSpecifications,
57                          boolean isMethod,
58                          boolean isConstructor)
59     {
60         // Get the referenced file set, or else this one.
61         MemberSpecificationElement memberSpecificationElement = isReference() ?
62             (MemberSpecificationElement)getCheckedRef(this.getClass(),
63                                                       this.getClass().getName()) :
64             this;
65 
66         // Create a new class member specification.
67         String access     = memberSpecificationElement.access;
68         String type       = memberSpecificationElement.type;
69         String annotation = memberSpecificationElement.annotation;
70         String name       = memberSpecificationElement.name;
71         String parameters = memberSpecificationElement.parameters;
72 
73         // Perform some basic conversions and checks on the attributes.
74         if (annotation != null)
75         {
76             annotation = ClassUtil.internalType(annotation);
77         }
78 
79         if (isMethod)
80         {
81             if (isConstructor)
82             {
83                 if (type != null)
84                 {
85                     throw new BuildException("Type attribute not allowed in constructor specification ["+type+"]");
86                 }
87 
88                 if (parameters != null)
89                 {
90                     type = JavaConstants.TYPE_VOID;
91                 }
92 
93                 name = ClassConstants.METHOD_NAME_INIT;
94             }
95             else if ((type != null) ^ (parameters != null))
96             {
97                 throw new BuildException("Type and parameters attributes must always be present in combination in method specification");
98             }
99         }
100         else
101         {
102             if (parameters != null)
103             {
104                 throw new BuildException("Parameters attribute not allowed in field specification ["+parameters+"]");
105             }
106         }
107 
108         List parameterList = ListUtil.commaSeparatedList(parameters);
109 
110         String descriptor =
111             parameters != null ? ClassUtil.internalMethodDescriptor(type, parameterList) :
112             type       != null ? ClassUtil.internalType(type)                            :
113                                  null;
114 
115         MemberSpecification memberSpecification =
116             new MemberSpecification(requiredAccessFlags(true,  access),
117                                     requiredAccessFlags(false, access),
118                                     annotation,
119                                     name,
120                                     descriptor);
121 
122         // Add it to the list.
123         memberSpecifications.add(memberSpecification);
124     }
125 
126 
127     // Ant task attributes.
128 
setAccess(String access)129     public void setAccess(String access)
130     {
131         this.access = access;
132     }
133 
134 
setAnnotation(String annotation)135     public void setAnnotation(String annotation)
136     {
137         this.annotation = annotation;
138     }
139 
140 
setType(String type)141     public void setType(String type)
142     {
143         this.type = type;
144     }
145 
146 
setName(String name)147     public void setName(String name)
148     {
149         this.name = name;
150     }
151 
152 
setParameters(String parameters)153     public void setParameters(String parameters)
154     {
155         this.parameters = parameters;
156     }
157 
158 
159     /**
160      * @deprecated Use {@link #setParameters(String)} instead.
161      */
setParam(String parameters)162     public void setParam(String parameters)
163     {
164         this.parameters = parameters;
165     }
166 
167 
168     // Small utility methods.
169 
requiredAccessFlags(boolean set, String access)170     private int requiredAccessFlags(boolean set,
171                                     String  access)
172     throws BuildException
173     {
174         int accessFlags = 0;
175 
176         if (access != null)
177         {
178             StringTokenizer tokenizer = new StringTokenizer(access, " ,");
179             while (tokenizer.hasMoreTokens())
180             {
181                 String token = tokenizer.nextToken();
182 
183                 if (token.startsWith("!") ^ set)
184                 {
185                     String strippedToken = token.startsWith("!") ?
186                         token.substring(1) :
187                         token;
188 
189                     int accessFlag =
190                         strippedToken.equals(JavaConstants.ACC_PUBLIC)       ? ClassConstants.ACC_PUBLIC       :
191                         strippedToken.equals(JavaConstants.ACC_PRIVATE)      ? ClassConstants.ACC_PRIVATE      :
192                         strippedToken.equals(JavaConstants.ACC_PROTECTED)    ? ClassConstants.ACC_PROTECTED    :
193                         strippedToken.equals(JavaConstants.ACC_STATIC)       ? ClassConstants.ACC_STATIC       :
194                         strippedToken.equals(JavaConstants.ACC_FINAL)        ? ClassConstants.ACC_FINAL        :
195                         strippedToken.equals(JavaConstants.ACC_SYNCHRONIZED) ? ClassConstants.ACC_SYNCHRONIZED :
196                         strippedToken.equals(JavaConstants.ACC_VOLATILE)     ? ClassConstants.ACC_VOLATILE     :
197                         strippedToken.equals(JavaConstants.ACC_TRANSIENT)    ? ClassConstants.ACC_TRANSIENT    :
198                         strippedToken.equals(JavaConstants.ACC_BRIDGE)       ? ClassConstants.ACC_BRIDGE       :
199                         strippedToken.equals(JavaConstants.ACC_VARARGS)      ? ClassConstants.ACC_VARARGS      :
200                         strippedToken.equals(JavaConstants.ACC_NATIVE)       ? ClassConstants.ACC_NATIVE       :
201                         strippedToken.equals(JavaConstants.ACC_ABSTRACT)     ? ClassConstants.ACC_ABSTRACT     :
202                         strippedToken.equals(JavaConstants.ACC_STRICT)       ? ClassConstants.ACC_STRICT       :
203                         strippedToken.equals(JavaConstants.ACC_SYNTHETIC)    ? ClassConstants.ACC_SYNTHETIC    :
204                                                                                0;
205 
206                     if (accessFlag == 0)
207                     {
208                         throw new BuildException("Incorrect class member access modifier ["+strippedToken+"]");
209                     }
210 
211                     accessFlags |= accessFlag;
212                 }
213             }
214         }
215 
216         return accessFlags;
217     }
218 }
219