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 static com.android.dx.rop.annotation.AnnotationVisibility.SYSTEM;
21import com.android.dx.rop.annotation.NameValuePair;
22import com.android.dx.rop.cst.Constant;
23import com.android.dx.rop.cst.CstAnnotation;
24import com.android.dx.rop.cst.CstArray;
25import com.android.dx.rop.cst.CstInteger;
26import com.android.dx.rop.cst.CstKnownNull;
27import com.android.dx.rop.cst.CstMethodRef;
28import com.android.dx.rop.cst.CstString;
29import com.android.dx.rop.cst.CstType;
30import com.android.dx.rop.type.Type;
31import com.android.dx.rop.type.TypeList;
32import java.util.ArrayList;
33
34/**
35 * Utility class for dealing with annotations.
36 */
37public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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