• 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.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      */
AnnotationUtils()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      */
makeAnnotationDefault(Annotation defaults)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      */
makeEnclosingClass(CstType clazz)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      */
makeEnclosingMethod(CstMethodRef method)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      */
makeInnerClass(CstUtf8 name, int accessFlags)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      */
makeMemberClasses(TypeList types)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      */
makeSignature(CstUtf8 signature)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      */
makeThrows(TypeList types)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      */
makeCstArray(TypeList types)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