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;
25
26import java.util.ArrayList;
27
28/**
29 * Association of a method and its parameter annotations.
30 */
31public final class ParameterAnnotationStruct
32        implements ToHuman, Comparable<ParameterAnnotationStruct> {
33    /** {@code non-null;} the method in question */
34    private final CstMethodRef method;
35
36    /** {@code non-null;} the associated annotations list */
37    private final AnnotationsList annotationsList;
38
39    /** {@code non-null;} the associated annotations list, as an item */
40    private final UniformListItem<AnnotationSetRefItem> annotationsItem;
41
42    /**
43     * Constructs an instance.
44     *
45     * @param method {@code non-null;} the method in question
46     * @param annotationsList {@code non-null;} the associated annotations list
47     */
48    public ParameterAnnotationStruct(CstMethodRef method,
49            AnnotationsList annotationsList) {
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);
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    public int hashCode() {
82        return method.hashCode();
83    }
84
85    /** {@inheritDoc} */
86    public boolean equals(Object other) {
87        if (! (other instanceof ParameterAnnotationStruct)) {
88            return false;
89        }
90
91        return method.equals(((ParameterAnnotationStruct) other).method);
92    }
93
94    /** {@inheritDoc} */
95    public int compareTo(ParameterAnnotationStruct other) {
96        return method.compareTo(other.method);
97    }
98
99    /** {@inheritDoc} */
100    public void addContents(DexFile file) {
101        MethodIdsSection methodIds = file.getMethodIds();
102        MixedItemSection wordData = file.getWordData();
103
104        methodIds.intern(method);
105        wordData.add(annotationsItem);
106    }
107
108    /** {@inheritDoc} */
109    public void writeTo(DexFile file, AnnotatedOutput out) {
110        int methodIdx = file.getMethodIds().indexOf(method);
111        int annotationsOff = annotationsItem.getAbsoluteOffset();
112
113        if (out.annotates()) {
114            out.annotate(0, "    " + method.toHuman());
115            out.annotate(4, "      method_idx:      " + Hex.u4(methodIdx));
116            out.annotate(4, "      annotations_off: " +
117                    Hex.u4(annotationsOff));
118        }
119
120        out.writeInt(methodIdx);
121        out.writeInt(annotationsOff);
122    }
123
124    /** {@inheritDoc} */
125    public String toHuman() {
126        StringBuilder sb = new StringBuilder();
127
128        sb.append(method.toHuman());
129        sb.append(": ");
130
131        boolean first = true;
132        for (AnnotationSetRefItem item : annotationsItem.getItems()) {
133            if (first) {
134                first = false;
135            } else {
136                sb.append(", ");
137            }
138            sb.append(item.toHuman());
139        }
140
141        return sb.toString();
142    }
143
144    /**
145     * Gets the method this item is for.
146     *
147     * @return {@code non-null;} the method
148     */
149    public CstMethodRef getMethod() {
150        return method;
151    }
152
153    /**
154     * Gets the associated annotations list.
155     *
156     * @return {@code non-null;} the annotations list
157     */
158    public AnnotationsList getAnnotationsList() {
159        return annotationsList;
160    }
161}
162