blob: 109583e6fbd93fe2b1289b8e3d40c2aea24701c7 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.dex.file;
import static com.android.dx.rop.annotation.AnnotationVisibility.SYSTEM;
import com.android.dx.rop.annotation.Annotation;
import com.android.dx.rop.annotation.NameValuePair;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstAnnotation;
import com.android.dx.rop.cst.CstArray;
import com.android.dx.rop.cst.CstInteger;
import com.android.dx.rop.cst.CstKnownNull;
import com.android.dx.rop.cst.CstMethodRef;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeList;
import java.util.ArrayList;
/**
* Utility class for dealing with annotations.
*/
public final class AnnotationUtils {
/** {@code non-null;} type for {@code AnnotationDefault} annotations */
private static final CstType ANNOTATION_DEFAULT_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
/** {@code non-null;} type for {@code EnclosingClass} annotations */
private static final CstType ENCLOSING_CLASS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
/** {@code non-null;} type for {@code EnclosingMethod} annotations */
private static final CstType ENCLOSING_METHOD_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
/** {@code non-null;} type for {@code InnerClass} annotations */
private static final CstType INNER_CLASS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
/** {@code non-null;} type for {@code MemberClasses} annotations */
private static final CstType MEMBER_CLASSES_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
/** {@code non-null;} type for {@code Signature} annotations */
private static final CstType SIGNATURE_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
/** {@code non-null;} type for {@code SourceDebugExtension} annotations */
private static final CstType SOURCE_DEBUG_EXTENSION_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/SourceDebugExtension;"));
/** {@code non-null;} type for {@code Throws} annotations */
private static final CstType THROWS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
/** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
private static final CstString ACCESS_FLAGS_STRING = new CstString("accessFlags");
/** {@code non-null;} the UTF-8 constant {@code "name"} */
private static final CstString NAME_STRING = new CstString("name");
/** {@code non-null;} the UTF-8 constant {@code "value"} */
private static final CstString VALUE_STRING = new CstString("value");
/**
* This class is uninstantiable.
*/
private AnnotationUtils() {
// This space intentionally left blank.
}
/**
* Constructs a standard {@code AnnotationDefault} annotation.
*
* @param defaults {@code non-null;} the defaults, itself as an annotation
* @return {@code non-null;} the constructed annotation
*/
public static Annotation makeAnnotationDefault(Annotation defaults) {
Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM);
result.put(new NameValuePair(VALUE_STRING, new CstAnnotation(defaults)));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code EnclosingClass} annotation.
*
* @param clazz {@code non-null;} the enclosing class
* @return {@code non-null;} the annotation
*/
public static Annotation makeEnclosingClass(CstType clazz) {
Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM);
result.put(new NameValuePair(VALUE_STRING, clazz));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code EnclosingMethod} annotation.
*
* @param method {@code non-null;} the enclosing method
* @return {@code non-null;} the annotation
*/
public static Annotation makeEnclosingMethod(CstMethodRef method) {
Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM);
result.put(new NameValuePair(VALUE_STRING, method));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code InnerClass} annotation.
*
* @param name {@code null-ok;} the original name of the class, or
* {@code null} to represent an anonymous class
* @param accessFlags the original access flags
* @return {@code non-null;} the annotation
*/
public static Annotation makeInnerClass(CstString name, int accessFlags) {
Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE;
result.put(new NameValuePair(NAME_STRING, nameCst));
result.put(new NameValuePair(ACCESS_FLAGS_STRING,
CstInteger.make(accessFlags)));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code MemberClasses} annotation.
*
* @param types {@code non-null;} the list of (the types of) the member classes
* @return {@code non-null;} the annotation
*/
public static Annotation makeMemberClasses(TypeList types) {
CstArray array = makeCstArray(types);
Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM);
result.put(new NameValuePair(VALUE_STRING, array));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code Signature} annotation.
*
* @param signature {@code non-null;} the signature string
* @return {@code non-null;} the annotation
*/
public static Annotation makeSignature(CstString signature) {
Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM);
/*
* Split the string into pieces that are likely to be common
* across many signatures and the rest of the file.
*/
String raw = signature.getString();
int rawLength = raw.length();
ArrayList<String> pieces = new ArrayList<String>(20);
for (int at = 0; at < rawLength; /*at*/) {
char c = raw.charAt(at);
int endAt = at + 1;
if (c == 'L') {
// Scan to ';' or '<'. Consume ';' but not '<'.
while (endAt < rawLength) {
c = raw.charAt(endAt);
if (c == ';') {
endAt++;
break;
} else if (c == '<') {
break;
}
endAt++;
}
} else {
// Scan to 'L' without consuming it.
while (endAt < rawLength) {
c = raw.charAt(endAt);
if (c == 'L') {
break;
}
endAt++;
}
}
pieces.add(raw.substring(at, endAt));
at = endAt;
}
int size = pieces.size();
CstArray.List list = new CstArray.List(size);
for (int i = 0; i < size; i++) {
list.set(i, new CstString(pieces.get(i)));
}
list.setImmutable();
result.put(new NameValuePair(VALUE_STRING, new CstArray(list)));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code SourceDebugExtension} annotation.
*
* @param smapString {@code non-null;} the SMAP string associated with
* @return {@code non-null;} the annotation
*/
public static Annotation makeSourceDebugExtension(CstString smapString) {
Annotation result = new Annotation(SOURCE_DEBUG_EXTENSION_TYPE, SYSTEM);
result.put(new NameValuePair(VALUE_STRING, smapString));
result.setImmutable();
return result;
}
/**
* Constructs a standard {@code Throws} annotation.
*
* @param types {@code non-null;} the list of thrown types
* @return {@code non-null;} the annotation
*/
public static Annotation makeThrows(TypeList types) {
CstArray array = makeCstArray(types);
Annotation result = new Annotation(THROWS_TYPE, SYSTEM);
result.put(new NameValuePair(VALUE_STRING, array));
result.setImmutable();
return result;
}
/**
* Converts a {@link TypeList} to a {@link CstArray}.
*
* @param types {@code non-null;} the type list
* @return {@code non-null;} the corresponding array constant
*/
private static CstArray makeCstArray(TypeList types) {
int size = types.size();
CstArray.List list = new CstArray.List(size);
for (int i = 0; i < size; i++) {
list.set(i, CstType.intern(types.getType(i)));
}
list.setImmutable();
return new CstArray(list);
}
}