Home | History | Annotate | Download | only in file
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dexgen.dex.file;
     18 
     19 import com.android.dexgen.rop.annotation.Annotation;
     20 import com.android.dexgen.rop.annotation.NameValuePair;
     21 import com.android.dexgen.rop.cst.Constant;
     22 import com.android.dexgen.rop.cst.CstAnnotation;
     23 import com.android.dexgen.rop.cst.CstArray;
     24 import com.android.dexgen.rop.cst.CstInteger;
     25 import com.android.dexgen.rop.cst.CstKnownNull;
     26 import com.android.dexgen.rop.cst.CstMethodRef;
     27 import com.android.dexgen.rop.cst.CstString;
     28 import com.android.dexgen.rop.cst.CstType;
     29 import com.android.dexgen.rop.cst.CstUtf8;
     30 import com.android.dexgen.rop.type.Type;
     31 import com.android.dexgen.rop.type.TypeList;
     32 
     33 import java.util.ArrayList;
     34 
     35 import static com.android.dexgen.rop.annotation.AnnotationVisibility.*;
     36 
     37 /**
     38  * Utility class for dealing with annotations.
     39  */
     40 public final class AnnotationUtils {
     41     /** {@code non-null;} type for {@code AnnotationDefault} annotations */
     42     private static final CstType ANNOTATION_DEFAULT_TYPE =
     43         CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
     44 
     45     /** {@code non-null;} type for {@code EnclosingClass} annotations */
     46     private static final CstType ENCLOSING_CLASS_TYPE =
     47         CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
     48 
     49     /** {@code non-null;} type for {@code EnclosingMethod} annotations */
     50     private static final CstType ENCLOSING_METHOD_TYPE =
     51         CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
     52 
     53     /** {@code non-null;} type for {@code InnerClass} annotations */
     54     private static final CstType INNER_CLASS_TYPE =
     55         CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
     56 
     57     /** {@code non-null;} type for {@code MemberClasses} annotations */
     58     private static final CstType MEMBER_CLASSES_TYPE =
     59         CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
     60 
     61     /** {@code non-null;} type for {@code Signature} annotations */
     62     private static final CstType SIGNATURE_TYPE =
     63         CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
     64 
     65     /** {@code non-null;} type for {@code Throws} annotations */
     66     private static final CstType THROWS_TYPE =
     67         CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
     68 
     69     /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
     70     private static final CstUtf8 ACCESS_FLAGS_UTF = new CstUtf8("accessFlags");
     71 
     72     /** {@code non-null;} the UTF-8 constant {@code "name"} */
     73     private static final CstUtf8 NAME_UTF = new CstUtf8("name");
     74 
     75     /** {@code non-null;} the UTF-8 constant {@code "value"} */
     76     private static final CstUtf8 VALUE_UTF = new CstUtf8("value");
     77 
     78     /**
     79      * This class is uninstantiable.
     80      */
     81     private AnnotationUtils() {
     82         // This space intentionally left blank.
     83     }
     84 
     85     /**
     86      * Constructs a standard {@code AnnotationDefault} annotation.
     87      *
     88      * @param defaults {@code non-null;} the defaults, itself as an annotation
     89      * @return {@code non-null;} the constructed annotation
     90      */
     91     public static Annotation makeAnnotationDefault(Annotation defaults) {
     92         Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM);
     93 
     94         result.put(new NameValuePair(VALUE_UTF, new CstAnnotation(defaults)));
     95         result.setImmutable();
     96         return result;
     97     }
     98 
     99     /**
    100      * Constructs a standard {@code EnclosingClass} annotation.
    101      *
    102      * @param clazz {@code non-null;} the enclosing class
    103      * @return {@code non-null;} the annotation
    104      */
    105     public static Annotation makeEnclosingClass(CstType clazz) {
    106         Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM);
    107 
    108         result.put(new NameValuePair(VALUE_UTF, clazz));
    109         result.setImmutable();
    110         return result;
    111     }
    112 
    113     /**
    114      * Constructs a standard {@code EnclosingMethod} annotation.
    115      *
    116      * @param method {@code non-null;} the enclosing method
    117      * @return {@code non-null;} the annotation
    118      */
    119     public static Annotation makeEnclosingMethod(CstMethodRef method) {
    120         Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM);
    121 
    122         result.put(new NameValuePair(VALUE_UTF, method));
    123         result.setImmutable();
    124         return result;
    125     }
    126 
    127     /**
    128      * Constructs a standard {@code InnerClass} annotation.
    129      *
    130      * @param name {@code null-ok;} the original name of the class, or
    131      * {@code null} to represent an anonymous class
    132      * @param accessFlags the original access flags
    133      * @return {@code non-null;} the annotation
    134      */
    135     public static Annotation makeInnerClass(CstUtf8 name, int accessFlags) {
    136         Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
    137         Constant nameCst =
    138             (name != null) ? new CstString(name) : CstKnownNull.THE_ONE;
    139 
    140         result.put(new NameValuePair(NAME_UTF, nameCst));
    141         result.put(new NameValuePair(ACCESS_FLAGS_UTF,
    142                         CstInteger.make(accessFlags)));
    143         result.setImmutable();
    144         return result;
    145     }
    146 
    147     /**
    148      * Constructs a standard {@code MemberClasses} annotation.
    149      *
    150      * @param types {@code non-null;} the list of (the types of) the member classes
    151      * @return {@code non-null;} the annotation
    152      */
    153     public static Annotation makeMemberClasses(TypeList types) {
    154         CstArray array = makeCstArray(types);
    155         Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM);
    156         result.put(new NameValuePair(VALUE_UTF, array));
    157         result.setImmutable();
    158         return result;
    159     }
    160 
    161     /**
    162      * Constructs a standard {@code Signature} annotation.
    163      *
    164      * @param signature {@code non-null;} the signature string
    165      * @return {@code non-null;} the annotation
    166      */
    167     public static Annotation makeSignature(CstUtf8 signature) {
    168         Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM);
    169 
    170         /*
    171          * Split the string into pieces that are likely to be common
    172          * across many signatures and the rest of the file.
    173          */
    174 
    175         String raw = signature.getString();
    176         int rawLength = raw.length();
    177         ArrayList<String> pieces = new ArrayList<String>(20);
    178 
    179         for (int at = 0; at < rawLength; /*at*/) {
    180             char c = raw.charAt(at);
    181             int endAt = at + 1;
    182             if (c == 'L') {
    183                 // Scan to ';' or '<'. Consume ';' but not '<'.
    184                 while (endAt < rawLength) {
    185                     c = raw.charAt(endAt);
    186                     if (c == ';') {
    187                         endAt++;
    188                         break;
    189                     } else if (c == '<') {
    190                         break;
    191                     }
    192                     endAt++;
    193                 }
    194             } else {
    195                 // Scan to 'L' without consuming it.
    196                 while (endAt < rawLength) {
    197                     c = raw.charAt(endAt);
    198                     if (c == 'L') {
    199                         break;
    200                     }
    201                     endAt++;
    202                 }
    203             }
    204 
    205             pieces.add(raw.substring(at, endAt));
    206             at = endAt;
    207         }
    208 
    209         int size = pieces.size();
    210         CstArray.List list = new CstArray.List(size);
    211 
    212         for (int i = 0; i < size; i++) {
    213             list.set(i, new CstString(pieces.get(i)));
    214         }
    215 
    216         list.setImmutable();
    217 
    218         result.put(new NameValuePair(VALUE_UTF, new CstArray(list)));
    219         result.setImmutable();
    220         return result;
    221     }
    222 
    223     /**
    224      * Constructs a standard {@code Throws} annotation.
    225      *
    226      * @param types {@code non-null;} the list of thrown types
    227      * @return {@code non-null;} the annotation
    228      */
    229     public static Annotation makeThrows(TypeList types) {
    230         CstArray array = makeCstArray(types);
    231         Annotation result = new Annotation(THROWS_TYPE, SYSTEM);
    232         result.put(new NameValuePair(VALUE_UTF, array));
    233         result.setImmutable();
    234         return result;
    235     }
    236 
    237     /**
    238      * Converts a {@link TypeList} to a {@link CstArray}.
    239      *
    240      * @param types {@code non-null;} the type list
    241      * @return {@code non-null;} the corresponding array constant
    242      */
    243     private static CstArray makeCstArray(TypeList types) {
    244         int size = types.size();
    245         CstArray.List list = new CstArray.List(size);
    246 
    247         for (int i = 0; i < size; i++) {
    248             list.set(i, CstType.intern(types.getType(i)));
    249         }
    250 
    251         list.setImmutable();
    252         return new CstArray(list);
    253     }
    254 }
    255