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 static com.android.dx.rop.annotation.AnnotationVisibility.SYSTEM; 20 21import com.android.dx.rop.annotation.Annotation; 22import com.android.dx.rop.annotation.NameValuePair; 23import com.android.dx.rop.cst.Constant; 24import com.android.dx.rop.cst.CstAnnotation; 25import com.android.dx.rop.cst.CstArray; 26import com.android.dx.rop.cst.CstInteger; 27import com.android.dx.rop.cst.CstKnownNull; 28import com.android.dx.rop.cst.CstMethodRef; 29import com.android.dx.rop.cst.CstString; 30import com.android.dx.rop.cst.CstType; 31import com.android.dx.rop.type.Type; 32import com.android.dx.rop.type.TypeList; 33 34import java.util.ArrayList; 35 36/** 37 * Utility class for dealing with annotations. 38 */ 39public final class AnnotationUtils { 40 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 CstString ACCESS_FLAGS_STRING = new CstString("accessFlags"); 71 72 /** {@code non-null;} the UTF-8 constant {@code "name"} */ 73 private static final CstString NAME_STRING = new CstString("name"); 74 75 /** {@code non-null;} the UTF-8 constant {@code "value"} */ 76 private static final CstString VALUE_STRING = new CstString("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_STRING, 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_STRING, 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_STRING, 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(CstString name, int accessFlags) { 136 Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM); 137 Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE; 138 139 result.put(new NameValuePair(NAME_STRING, nameCst)); 140 result.put(new NameValuePair(ACCESS_FLAGS_STRING, 141 CstInteger.make(accessFlags))); 142 result.setImmutable(); 143 return result; 144 } 145 146 /** 147 * Constructs a standard {@code MemberClasses} annotation. 148 * 149 * @param types {@code non-null;} the list of (the types of) the member classes 150 * @return {@code non-null;} the annotation 151 */ 152 public static Annotation makeMemberClasses(TypeList types) { 153 CstArray array = makeCstArray(types); 154 Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM); 155 result.put(new NameValuePair(VALUE_STRING, array)); 156 result.setImmutable(); 157 return result; 158 } 159 160 /** 161 * Constructs a standard {@code Signature} annotation. 162 * 163 * @param signature {@code non-null;} the signature string 164 * @return {@code non-null;} the annotation 165 */ 166 public static Annotation makeSignature(CstString signature) { 167 Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM); 168 169 /* 170 * Split the string into pieces that are likely to be common 171 * across many signatures and the rest of the file. 172 */ 173 174 String raw = signature.getString(); 175 int rawLength = raw.length(); 176 ArrayList<String> pieces = new ArrayList<String>(20); 177 178 for (int at = 0; at < rawLength; /*at*/) { 179 char c = raw.charAt(at); 180 int endAt = at + 1; 181 if (c == 'L') { 182 // Scan to ';' or '<'. Consume ';' but not '<'. 183 while (endAt < rawLength) { 184 c = raw.charAt(endAt); 185 if (c == ';') { 186 endAt++; 187 break; 188 } else if (c == '<') { 189 break; 190 } 191 endAt++; 192 } 193 } else { 194 // Scan to 'L' without consuming it. 195 while (endAt < rawLength) { 196 c = raw.charAt(endAt); 197 if (c == 'L') { 198 break; 199 } 200 endAt++; 201 } 202 } 203 204 pieces.add(raw.substring(at, endAt)); 205 at = endAt; 206 } 207 208 int size = pieces.size(); 209 CstArray.List list = new CstArray.List(size); 210 211 for (int i = 0; i < size; i++) { 212 list.set(i, new CstString(pieces.get(i))); 213 } 214 215 list.setImmutable(); 216 217 result.put(new NameValuePair(VALUE_STRING, new CstArray(list))); 218 result.setImmutable(); 219 return result; 220 } 221 222 /** 223 * Constructs a standard {@code Throws} annotation. 224 * 225 * @param types {@code non-null;} the list of thrown types 226 * @return {@code non-null;} the annotation 227 */ 228 public static Annotation makeThrows(TypeList types) { 229 CstArray array = makeCstArray(types); 230 Annotation result = new Annotation(THROWS_TYPE, SYSTEM); 231 result.put(new NameValuePair(VALUE_STRING, array)); 232 result.setImmutable(); 233 return result; 234 } 235 236 /** 237 * Converts a {@link TypeList} to a {@link CstArray}. 238 * 239 * @param types {@code non-null;} the type list 240 * @return {@code non-null;} the corresponding array constant 241 */ 242 private static CstArray makeCstArray(TypeList types) { 243 int size = types.size(); 244 CstArray.List list = new CstArray.List(size); 245 246 for (int i = 0; i < size; i++) { 247 list.set(i, CstType.intern(types.getType(i))); 248 } 249 250 list.setImmutable(); 251 return new CstArray(list); 252 } 253} 254