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