AnnotationUtils.java revision 99409883d9c4c0ffb49b070ce307bb33a9dfe9f1
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
17package com.android.dx.dex.file;
18
19import com.android.dx.rop.annotation.Annotation;
20import com.android.dx.rop.annotation.NameValuePair;
21import com.android.dx.rop.cst.Constant;
22import com.android.dx.rop.cst.CstAnnotation;
23import com.android.dx.rop.cst.CstArray;
24import com.android.dx.rop.cst.CstInteger;
25import com.android.dx.rop.cst.CstKnownNull;
26import com.android.dx.rop.cst.CstMethodRef;
27import com.android.dx.rop.cst.CstString;
28import com.android.dx.rop.cst.CstType;
29import com.android.dx.rop.cst.CstUtf8;
30import com.android.dx.rop.type.Type;
31import com.android.dx.rop.type.TypeList;
32
33import java.util.ArrayList;
34
35import static com.android.dx.rop.annotation.AnnotationVisibility.*;
36
37/**
38 * Utility class for dealing with annotations.
39 */
40public 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