Home | History | Annotate | Download | only in ant
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) 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      */
     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 
    129     public void setAccess(String access)
    130     {
    131         this.access = access;
    132     }
    133 
    134 
    135     public void setAnnotation(String annotation)
    136     {
    137         this.annotation = annotation;
    138     }
    139 
    140 
    141     public void setType(String type)
    142     {
    143         this.type = type;
    144     }
    145 
    146 
    147     public void setName(String name)
    148     {
    149         this.name = name;
    150     }
    151 
    152 
    153     public void setParameters(String parameters)
    154     {
    155         this.parameters = parameters;
    156     }
    157 
    158 
    159     /**
    160      * @deprecated Use {@link #setParameters(String)} instead.
    161      */
    162     public void setParam(String parameters)
    163     {
    164         this.parameters = parameters;
    165     }
    166 
    167 
    168     // Small utility methods.
    169 
    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