001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 *
017 */
018package org.apache.bcel.classfile;
019
020import java.io.DataInput;
021import java.io.IOException;
022import java.util.Objects;
023
024import org.apache.bcel.Const;
025import org.apache.bcel.generic.Type;
026import org.apache.bcel.util.BCELComparator;
027
028/**
029 * This class represents the method info structure, i.e., the representation
030 * for a method in the class. See JVM specification for details.
031 * A method has access flags, a name, a signature and a number of attributes.
032 *
033 */
034public final class Method extends FieldOrMethod {
035
036    private static BCELComparator bcelComparator = new BCELComparator() {
037
038        @Override
039        public boolean equals( final Object o1, final Object o2 ) {
040            final Method THIS = (Method) o1;
041            final Method THAT = (Method) o2;
042            return Objects.equals(THIS.getName(), THAT.getName())
043                    && Objects.equals(THIS.getSignature(), THAT.getSignature());
044        }
045
046
047        @Override
048        public int hashCode( final Object o ) {
049            final Method THIS = (Method) o;
050            return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
051        }
052    };
053
054    // annotations defined on the parameters of a method
055    private ParameterAnnotationEntry[] parameterAnnotationEntries;
056
057    /**
058     * Empty constructor, all attributes have to be defined via `setXXX'
059     * methods. Use at your own risk.
060     */
061    public Method() {
062    }
063
064
065    /**
066     * Initialize from another object. Note that both objects use the same
067     * references (shallow copy). Use clone() for a physical copy.
068     */
069    public Method(final Method c) {
070        super(c);
071    }
072
073
074    /**
075     * Construct object from file stream.
076     * @param file Input stream
077     * @throws IOException
078     * @throws ClassFormatException
079     */
080    Method(final DataInput file, final ConstantPool constant_pool) throws IOException,
081            ClassFormatException {
082        super(file, constant_pool);
083    }
084
085
086    /**
087     * @param access_flags Access rights of method
088     * @param name_index Points to field name in constant pool
089     * @param signature_index Points to encoded signature
090     * @param attributes Collection of attributes
091     * @param constant_pool Array of constants
092     */
093    public Method(final int access_flags, final int name_index, final int signature_index, final Attribute[] attributes,
094            final ConstantPool constant_pool) {
095        super(access_flags, name_index, signature_index, attributes, constant_pool);
096    }
097
098
099    /**
100     * Called by objects that are traversing the nodes of the tree implicitely
101     * defined by the contents of a Java class. I.e., the hierarchy of methods,
102     * fields, attributes, etc. spawns a tree of objects.
103     *
104     * @param v Visitor object
105     */
106    @Override
107    public void accept( final Visitor v ) {
108        v.visitMethod(this);
109    }
110
111
112    /**
113     * @return Code attribute of method, if any
114     */
115    public Code getCode() {
116        for (final Attribute attribute : super.getAttributes()) {
117            if (attribute instanceof Code) {
118                return (Code) attribute;
119            }
120        }
121        return null;
122    }
123
124
125    /**
126     * @return ExceptionTable attribute of method, if any, i.e., list all
127     * exceptions the method may throw not exception handlers!
128     */
129    public ExceptionTable getExceptionTable() {
130        for (final Attribute attribute : super.getAttributes()) {
131            if (attribute instanceof ExceptionTable) {
132                return (ExceptionTable) attribute;
133            }
134        }
135        return null;
136    }
137
138
139    /** @return LocalVariableTable of code attribute if any, i.e. the call is forwarded
140     * to the Code atribute.
141     */
142    public LocalVariableTable getLocalVariableTable() {
143        final Code code = getCode();
144        if (code == null) {
145            return null;
146        }
147        return code.getLocalVariableTable();
148    }
149
150
151    /** @return LineNumberTable of code attribute if any, i.e. the call is forwarded
152     * to the Code atribute.
153     */
154    public LineNumberTable getLineNumberTable() {
155        final Code code = getCode();
156        if (code == null) {
157            return null;
158        }
159        return code.getLineNumberTable();
160    }
161
162
163    /**
164     * Return string representation close to declaration format,
165     * `public static void main(String[] args) throws IOException', e.g.
166     *
167     * @return String representation of the method.
168     */
169    @Override
170    public String toString() {
171        final String access = Utility.accessToString(super.getAccessFlags());
172        // Get name and signature from constant pool
173        ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(super.getSignatureIndex(), Const.CONSTANT_Utf8);
174        String signature = c.getBytes();
175        c = (ConstantUtf8) super.getConstantPool().getConstant(super.getNameIndex(), Const.CONSTANT_Utf8);
176        final String name = c.getBytes();
177        signature = Utility.methodSignatureToString(signature, name, access, true,
178                getLocalVariableTable());
179        final StringBuilder buf = new StringBuilder(signature);
180        for (final Attribute attribute : super.getAttributes()) {
181            if (!((attribute instanceof Code) || (attribute instanceof ExceptionTable))) {
182                buf.append(" [").append(attribute).append("]");
183            }
184        }
185        final ExceptionTable e = getExceptionTable();
186        if (e != null) {
187            final String str = e.toString();
188            if (!str.isEmpty()) {
189                buf.append("\n\t\tthrows ").append(str);
190            }
191        }
192        return buf.toString();
193    }
194
195
196    /**
197     * @return deep copy of this method
198     */
199    public Method copy( final ConstantPool _constant_pool ) {
200        return (Method) copy_(_constant_pool);
201    }
202
203
204    /**
205     * @return return type of method
206     */
207    public Type getReturnType() {
208        return Type.getReturnType(getSignature());
209    }
210
211
212    /**
213     * @return array of method argument types
214     */
215    public Type[] getArgumentTypes() {
216        return Type.getArgumentTypes(getSignature());
217    }
218
219
220    /**
221     * @return Comparison strategy object
222     */
223    public static BCELComparator getComparator() {
224        return bcelComparator;
225    }
226
227
228    /**
229     * @param comparator Comparison strategy object
230     */
231    public static void setComparator( final BCELComparator comparator ) {
232        bcelComparator = comparator;
233    }
234
235
236    /**
237     * Return value as defined by given BCELComparator strategy.
238     * By default two method objects are said to be equal when
239     * their names and signatures are equal.
240     *
241     * @see java.lang.Object#equals(java.lang.Object)
242     */
243    @Override
244    public boolean equals( final Object obj ) {
245        return bcelComparator.equals(this, obj);
246    }
247
248
249    /**
250     * Return value as defined by given BCELComparator strategy.
251     * By default return the hashcode of the method's name XOR signature.
252     *
253     * @see java.lang.Object#hashCode()
254     */
255    @Override
256    public int hashCode() {
257        return bcelComparator.hashCode(this);
258    }
259
260    /**
261     * @return Annotations on the parameters of a method
262     * @since 6.0
263     */
264    public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
265        if (parameterAnnotationEntries == null) {
266            parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
267        }
268        return parameterAnnotationEntries;
269    }
270}