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.Annotations;
20import com.android.dx.rop.annotation.AnnotationsList;
21import com.android.dx.rop.cst.CstMethodRef;
22import com.android.dx.util.AnnotatedOutput;
23import com.android.dx.util.Hex;
24import com.android.dx.util.ToHuman;
25import java.util.ArrayList;
26
27/**
28 * Association of a method and its parameter annotations.
29 */
30public final class ParameterAnnotationStruct
31        implements ToHuman, Comparable<ParameterAnnotationStruct> {
32    /** {@code non-null;} the method in question */
33    private final CstMethodRef method;
34
35    /** {@code non-null;} the associated annotations list */
36    private final AnnotationsList annotationsList;
37
38    /** {@code non-null;} the associated annotations list, as an item */
39    private final UniformListItem<AnnotationSetRefItem> annotationsItem;
40
41    /**
42     * Constructs an instance.
43     *
44     * @param method {@code non-null;} the method in question
45     * @param annotationsList {@code non-null;} the associated annotations list
46     * @param dexFile {@code non-null;} dex output
47     */
48    public ParameterAnnotationStruct(CstMethodRef method,
49            AnnotationsList annotationsList, DexFile dexFile) {
50        if (method == null) {
51            throw new NullPointerException("method == null");
52        }
53
54        if (annotationsList == null) {
55            throw new NullPointerException("annotationsList == null");
56        }
57
58        this.method = method;
59        this.annotationsList = annotationsList;
60
61        /*
62         * Construct an item for the annotations list. TODO: This
63         * requires way too much copying; fix it.
64         */
65
66        int size = annotationsList.size();
67        ArrayList<AnnotationSetRefItem> arrayList = new
68            ArrayList<AnnotationSetRefItem>(size);
69
70        for (int i = 0; i < size; i++) {
71            Annotations annotations = annotationsList.get(i);
72            AnnotationSetItem item = new AnnotationSetItem(annotations, dexFile);
73            arrayList.add(new AnnotationSetRefItem(item));
74        }
75
76        this.annotationsItem = new UniformListItem<AnnotationSetRefItem>(
77                ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList);
78    }
79
80    /** {@inheritDoc} */
81    @Override
82    public int hashCode() {
83        return method.hashCode();
84    }
85
86    /** {@inheritDoc} */
87    @Override
88    public boolean equals(Object other) {
89        if (! (other instanceof ParameterAnnotationStruct)) {
90            return false;
91        }
92
93        return method.equals(((ParameterAnnotationStruct) other).method);
94    }
95
96    /** {@inheritDoc} */
97    @Override
98    public int compareTo(ParameterAnnotationStruct other) {
99        return method.compareTo(other.method);
100    }
101
102    /** {@inheritDoc} */
103    public void addContents(DexFile file) {
104        MethodIdsSection methodIds = file.getMethodIds();
105        MixedItemSection wordData = file.getWordData();
106
107        methodIds.intern(method);
108        wordData.add(annotationsItem);
109    }
110
111    /** {@inheritDoc} */
112    public void writeTo(DexFile file, AnnotatedOutput out) {
113        int methodIdx = file.getMethodIds().indexOf(method);
114        int annotationsOff = annotationsItem.getAbsoluteOffset();
115
116        if (out.annotates()) {
117            out.annotate(0, "    " + method.toHuman());
118            out.annotate(4, "      method_idx:      " + Hex.u4(methodIdx));
119            out.annotate(4, "      annotations_off: " +
120                    Hex.u4(annotationsOff));
121        }
122
123        out.writeInt(methodIdx);
124        out.writeInt(annotationsOff);
125    }
126
127    /** {@inheritDoc} */
128    @Override
129    public String toHuman() {
130        StringBuilder sb = new StringBuilder();
131
132        sb.append(method.toHuman());
133        sb.append(": ");
134
135        boolean first = true;
136        for (AnnotationSetRefItem item : annotationsItem.getItems()) {
137            if (first) {
138                first = false;
139            } else {
140                sb.append(", ");
141            }
142            sb.append(item.toHuman());
143        }
144
145        return sb.toString();
146    }
147
148    /**
149     * Gets the method this item is for.
150     *
151     * @return {@code non-null;} the method
152     */
153    public CstMethodRef getMethod() {
154        return method;
155    }
156
157    /**
158     * Gets the associated annotations list.
159     *
160     * @return {@code non-null;} the annotations list
161     */
162    public AnnotationsList getAnnotationsList() {
163        return annotationsList;
164    }
165}
166