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