1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2007 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.mockito.asm;
31
32/**
33 * An {@link FieldVisitor} that generates Java fields in bytecode form.
34 *
35 * @author Eric Bruneton
36 */
37final class FieldWriter implements FieldVisitor {
38
39    /**
40     * Next field writer (see {@link ClassWriter#firstField firstField}).
41     */
42    FieldWriter next;
43
44    /**
45     * The class writer to which this field must be added.
46     */
47    private final ClassWriter cw;
48
49    /**
50     * Access flags of this field.
51     */
52    private final int access;
53
54    /**
55     * The index of the constant pool item that contains the name of this
56     * method.
57     */
58    private final int name;
59
60    /**
61     * The index of the constant pool item that contains the descriptor of this
62     * field.
63     */
64    private final int desc;
65
66    /**
67     * The index of the constant pool item that contains the signature of this
68     * field.
69     */
70    private int signature;
71
72    /**
73     * The index of the constant pool item that contains the constant value of
74     * this field.
75     */
76    private int value;
77
78    /**
79     * The runtime visible annotations of this field. May be <tt>null</tt>.
80     */
81    private AnnotationWriter anns;
82
83    /**
84     * The runtime invisible annotations of this field. May be <tt>null</tt>.
85     */
86    private AnnotationWriter ianns;
87
88    /**
89     * The non standard attributes of this field. May be <tt>null</tt>.
90     */
91    private Attribute attrs;
92
93    // ------------------------------------------------------------------------
94    // Constructor
95    // ------------------------------------------------------------------------
96
97    /**
98     * Constructs a new {@link FieldWriter}.
99     *
100     * @param cw the class writer to which this field must be added.
101     * @param access the field's access flags (see {@link Opcodes}).
102     * @param name the field's name.
103     * @param desc the field's descriptor (see {@link Type}).
104     * @param signature the field's signature. May be <tt>null</tt>.
105     * @param value the field's constant value. May be <tt>null</tt>.
106     */
107    FieldWriter(
108        final ClassWriter cw,
109        final int access,
110        final String name,
111        final String desc,
112        final String signature,
113        final Object value)
114    {
115        if (cw.firstField == null) {
116            cw.firstField = this;
117        } else {
118            cw.lastField.next = this;
119        }
120        cw.lastField = this;
121        this.cw = cw;
122        this.access = access;
123        this.name = cw.newUTF8(name);
124        this.desc = cw.newUTF8(desc);
125        if (ClassReader.SIGNATURES && signature != null) {
126            this.signature = cw.newUTF8(signature);
127        }
128        if (value != null) {
129            this.value = cw.newConstItem(value).index;
130        }
131    }
132
133    // ------------------------------------------------------------------------
134    // Implementation of the FieldVisitor interface
135    // ------------------------------------------------------------------------
136
137    public AnnotationVisitor visitAnnotation(
138        final String desc,
139        final boolean visible)
140    {
141        if (!ClassReader.ANNOTATIONS) {
142            return null;
143        }
144        ByteVector bv = new ByteVector();
145        // write type, and reserve space for values count
146        bv.putShort(cw.newUTF8(desc)).putShort(0);
147        AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
148        if (visible) {
149            aw.next = anns;
150            anns = aw;
151        } else {
152            aw.next = ianns;
153            ianns = aw;
154        }
155        return aw;
156    }
157
158    public void visitAttribute(final Attribute attr) {
159        attr.next = attrs;
160        attrs = attr;
161    }
162
163    public void visitEnd() {
164    }
165
166    // ------------------------------------------------------------------------
167    // Utility methods
168    // ------------------------------------------------------------------------
169
170    /**
171     * Returns the size of this field.
172     *
173     * @return the size of this field.
174     */
175    int getSize() {
176        int size = 8;
177        if (value != 0) {
178            cw.newUTF8("ConstantValue");
179            size += 8;
180        }
181        if ((access & Opcodes.ACC_SYNTHETIC) != 0
182                && (cw.version & 0xffff) < Opcodes.V1_5)
183        {
184            cw.newUTF8("Synthetic");
185            size += 6;
186        }
187        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
188            cw.newUTF8("Deprecated");
189            size += 6;
190        }
191        if (ClassReader.SIGNATURES && signature != 0) {
192            cw.newUTF8("Signature");
193            size += 8;
194        }
195        if (ClassReader.ANNOTATIONS && anns != null) {
196            cw.newUTF8("RuntimeVisibleAnnotations");
197            size += 8 + anns.getSize();
198        }
199        if (ClassReader.ANNOTATIONS && ianns != null) {
200            cw.newUTF8("RuntimeInvisibleAnnotations");
201            size += 8 + ianns.getSize();
202        }
203        if (attrs != null) {
204            size += attrs.getSize(cw, null, 0, -1, -1);
205        }
206        return size;
207    }
208
209    /**
210     * Puts the content of this field into the given byte vector.
211     *
212     * @param out where the content of this field must be put.
213     */
214    void put(final ByteVector out) {
215        out.putShort(access).putShort(name).putShort(desc);
216        int attributeCount = 0;
217        if (value != 0) {
218            ++attributeCount;
219        }
220        if ((access & Opcodes.ACC_SYNTHETIC) != 0
221                && (cw.version & 0xffff) < Opcodes.V1_5)
222        {
223            ++attributeCount;
224        }
225        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
226            ++attributeCount;
227        }
228        if (ClassReader.SIGNATURES && signature != 0) {
229            ++attributeCount;
230        }
231        if (ClassReader.ANNOTATIONS && anns != null) {
232            ++attributeCount;
233        }
234        if (ClassReader.ANNOTATIONS && ianns != null) {
235            ++attributeCount;
236        }
237        if (attrs != null) {
238            attributeCount += attrs.getCount();
239        }
240        out.putShort(attributeCount);
241        if (value != 0) {
242            out.putShort(cw.newUTF8("ConstantValue"));
243            out.putInt(2).putShort(value);
244        }
245        if ((access & Opcodes.ACC_SYNTHETIC) != 0
246                && (cw.version & 0xffff) < Opcodes.V1_5)
247        {
248            out.putShort(cw.newUTF8("Synthetic")).putInt(0);
249        }
250        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
251            out.putShort(cw.newUTF8("Deprecated")).putInt(0);
252        }
253        if (ClassReader.SIGNATURES && signature != 0) {
254            out.putShort(cw.newUTF8("Signature"));
255            out.putInt(2).putShort(signature);
256        }
257        if (ClassReader.ANNOTATIONS && anns != null) {
258            out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
259            anns.put(out);
260        }
261        if (ClassReader.ANNOTATIONS && ianns != null) {
262            out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
263            ianns.put(out);
264        }
265        if (attrs != null) {
266            attrs.put(cw, null, 0, -1, -1, out);
267        }
268    }
269}
270