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