org.spongepowered.asm.util.SignaturePrinter.java Source code

Java tutorial

Introduction

Here is the source code for org.spongepowered.asm.util.SignaturePrinter.java

Source

/*
 * This file is part of Sponge, licensed under the MIT License (MIT).
 *
 * Copyright (c) SpongePowered.org <http://www.spongepowered.org>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.spongepowered.asm.util;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;

import com.google.common.base.Strings;

/**
 * Generates callback signature for callback pretty-print
 */
public class SignaturePrinter {

    /**
     * Method name 
     */
    private final String name;

    /**
     * The return type of the <b>target</b> method (used to fill in the generic
     * bound on a CallbackInfoReturnable. 
     */
    private final Type returnType;

    /**
     * Argument type array (sparse, with no TOP entries) 
     */
    private final Type[] argTypes;

    /**
     * Argument names 
     */
    private final String[] argNames;

    /**
     * Method prefix
     */
    private String modifiers = "private void";

    public SignaturePrinter(MethodNode method) {
        this(method.name, Type.VOID_TYPE, Type.getArgumentTypes(method.desc));
        this.setModifiers(method);
    }

    public SignaturePrinter(MethodNode method, String[] argNames) {
        this(method.name, Type.VOID_TYPE, Type.getArgumentTypes(method.desc), argNames);
        this.setModifiers(method);
    }

    public SignaturePrinter(String name, String desc) {
        this(name, Type.getReturnType(desc), Type.getArgumentTypes(desc));
    }

    public SignaturePrinter(String name, Type returnType, Type[] args) {
        this.name = name;
        this.returnType = returnType;
        this.argTypes = new Type[args.length];
        this.argNames = new String[args.length];
        for (int l = 0, v = 0; l < args.length; l++) {
            if (args[l] != null) {
                this.argTypes[l] = args[l];
                this.argNames[l] = "var" + v++;
            }
        }
    }

    public SignaturePrinter(String name, Type returnType, LocalVariableNode[] args) {
        this.name = name;
        this.returnType = returnType;
        this.argTypes = new Type[args.length];
        this.argNames = new String[args.length];
        for (int l = 0; l < args.length; l++) {
            if (args[l] != null) {
                this.argTypes[l] = Type.getType(args[l].desc);
                this.argNames[l] = args[l].name;
            }
        }
    }

    public SignaturePrinter(String name, Type returnType, Type[] argTypes, String[] argNames) {
        this.name = name;
        this.returnType = returnType;
        this.argTypes = argTypes;
        this.argNames = argNames;
    }

    public void setModifiers(MethodNode method) {
        String returnType = SignaturePrinter.getTypeName(Type.getReturnType(method.desc), false);
        if ((method.access & Opcodes.ACC_PUBLIC) != 0) {
            this.setModifiers("public " + returnType);
        } else if ((method.access & Opcodes.ACC_PROTECTED) != 0) {
            this.setModifiers("protected " + returnType);
        } else if ((method.access & Opcodes.ACC_PRIVATE) != 0) {
            this.setModifiers("private " + returnType);
        } else {
            this.setModifiers(returnType);
        }
    }

    public void setModifiers(String modifiers) {
        this.modifiers = modifiers;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.modifiers).append(" ").append(this.name).append('(');
        for (int var = 0; var < this.argTypes.length; var++) {
            if (this.argTypes[var] == null) {
                continue;
            } else if (var > 0) {
                sb.append(", ");
            }
            String name = Strings.isNullOrEmpty(this.argNames[var]) ? "unnamed" + var : this.argNames[var];
            this.appendType(sb, this.argTypes[var], name);
        }
        sb.append(")");
        return sb.toString();
    }

    private StringBuilder appendType(StringBuilder sb, Type type, String name) {
        switch (type.getSort()) {
        case Type.ARRAY:
            return this.appendType(sb, type.getElementType(), name).append("[]");
        case Type.OBJECT:
            return this.appendType(sb, type.getClassName(), name);
        default:
            return sb.append(SignaturePrinter.getTypeName(type, false)).append(' ').append(name);
        }
    }

    private StringBuilder appendType(StringBuilder sb, String typeName, String name) {
        typeName = typeName.substring(typeName.lastIndexOf('.') + 1);
        sb.append(typeName);
        if (typeName.endsWith("CallbackInfoReturnable")) {
            sb.append('<').append(SignaturePrinter.getTypeName(this.returnType, true)).append('>');
        }
        return sb.append(' ').append(name);
    }

    /**
     * Get the source code name for the specified type
     * 
     * @param type Type to generate a friendly name for
     * @param box True to return the equivalent boxing type for primitives 
     * @return String representation of the specified type, eg "int" for an
     *         integer primitive or "String" for java.lang.String
     */
    public static String getTypeName(Type type, boolean box) {
        switch (type.getSort()) {
        case Type.VOID:
            return box ? "Void" : "void";
        case Type.BOOLEAN:
            return box ? "Boolean" : "boolean";
        case Type.CHAR:
            return box ? "Character" : "char";
        case Type.BYTE:
            return box ? "Byte" : "byte";
        case Type.SHORT:
            return box ? "Short" : "short";
        case Type.INT:
            return box ? "Integer" : "int";
        case Type.FLOAT:
            return box ? "Float" : "float";
        case Type.LONG:
            return box ? "Long" : "long";
        case Type.DOUBLE:
            return box ? "Double" : "double";
        case Type.ARRAY:
            return SignaturePrinter.getTypeName(type.getElementType(), box) + "[]";
        case Type.OBJECT:
            String typeName = type.getClassName();
            typeName = typeName.substring(typeName.lastIndexOf('.') + 1);
            return typeName;
        default:
            return "Object";
        }
    }
}