uniol.apt.tasks.modules.ModuleParameterVerifyMethodVisitor.java Source code

Java tutorial

Introduction

Here is the source code for uniol.apt.tasks.modules.ModuleParameterVerifyMethodVisitor.java

Source

/*-
 * APT - Analysis of Petri Nets and labeled Transition systems
 * Copyright (C) 2012-2013  Members of the project group APT
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package uniol.apt.tasks.modules;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import static org.objectweb.asm.Opcodes.ASM4;

/** @author vsp */
public class ModuleParameterVerifyMethodVisitor extends MethodVisitor {
    /**
     * Marker class, references to the Type of this class get used to mark that a parameter occurs with different
     * Types
     */
    private static interface DifferentTypesDetected {
        /* empty */ }

    static public final Type DIFFERENT_TYPES_DETECTED_TYPE = Type.getType(DifferentTypesDetected.class);
    private final String targetClass;
    private final String targetMethod;
    private final Map<String, Type> parameterMap = new HashMap<String, Type>() {
        public static final long serialVersionUID = 0xfee1deadL;

        @Override
        public Type put(String key, Type value) {
            Type old = get(key);

            if (old != null && !old.equals(value)) {
                value = DIFFERENT_TYPES_DETECTED_TYPE;
            }

            return super.put(key, value);
        }
    };

    /** The last loaded constant of type String */
    private String ldcLastString = null;
    /** A string constant which might be the name parameter of the method */
    private String ldcName = null;
    /** A class type constant which might be the klass parameter of the method */
    private Type ldcClass = null;

    /**
     * Constructor
     *
     * @param clazz Calls to which class or interface should be searched?
     * @param method Calls to which method should be searched?
     * @param mv next MethodVisitor (for chaining)
     */
    ModuleParameterVerifyMethodVisitor(Class<?> clazz, String method, MethodVisitor mv) {
        super(ASM4, mv);
        targetClass = Type.getType(clazz).getInternalName();
        targetMethod = method;
    }

    /**
     * Constructor
     *
     * @param clazz Calls to which class or interface should be searched?
     * @param method Calls to which method should be searched?
     */
    ModuleParameterVerifyMethodVisitor(Class<?> clazz, String method) {
        this(clazz, method, null);
    }

    @Override
    public void visitLdcInsn(Object cst) {
        super.visitLdcInsn(cst);

        if (cst instanceof String) {
            // constant is a string constant
            ldcLastString = (String) cst;
        } else if (cst instanceof Type) {
            // constant doesn't references a basic type
            Type typeCst = (Type) cst;
            switch (typeCst.getSort()) {
            case Type.ARRAY:
            case Type.OBJECT:
                // constant references a class, which could be the second parameter of the method
                // the string constant which we got before this could be the first parameter
                ldcClass = typeCst;
                ldcName = ldcLastString;
                break;
            default:
                /* do nothing */
            }
        }
    }

    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
        super.visitMethodInsn(opcode, owner, name, desc);

        if (owner.equals(targetClass) && name.equals(targetMethod)) {
            // the observed method get called
            if (ldcName != null && ldcClass != null) {
                parameterMap.put(ldcName, ldcClass);
            } else {
                // too complex program structure or the compiler didn't produced the expected bytecode
                // => silently fail
            }

            // we don't support nested calls of this methods => clear constants
            ldcLastString = null;
            ldcName = null;
            ldcClass = null;
        }
    }

    /**
     * @return Mapping of parameters to types or DIFFERENT_TYPES_DETECTED_TYPE if they have more than one type
     */
    Map<String, Type> getParameterMap() {
        return parameterMap;
    }
}

// vim: ft=java:noet:sw=8:sts=8:ts=8:tw=120