com.facebook.buck.jvm.java.abi.MethodMirror.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.jvm.java.abi.MethodMirror.java

Source

/*
 * Copyright 2014-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.facebook.buck.jvm.java.abi;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.SortedSet;

import javax.annotation.Nullable;

class MethodMirror extends MethodVisitor implements Comparable<MethodMirror> {
    private final String name;
    private final String desc;
    private final String signature;
    private final int access;
    private final String[] exceptions;
    private final SortedSet<AnnotationMirror> annotations;
    private final AnnotationMirror[] parameterAnnotations;
    @Nullable
    private AnnotationDefaultValueMirror annotationDefault;
    private final String key;

    public MethodMirror(int access, String name, String desc, String signature, String[] exceptions) {
        super(Opcodes.ASM5);

        this.access = access;
        this.name = name;
        this.desc = Preconditions.checkNotNull(desc);
        this.signature = signature;
        this.exceptions = exceptions;

        this.annotations = Sets.newTreeSet();

        int paramCount = countParameters(desc);
        this.parameterAnnotations = new AnnotationMirror[paramCount];

        this.key = name + desc + paramCount;
    }

    private int countParameters(String desc) {
        int count = 0;

        char[] chars = desc.toCharArray();

        // Find the opening parenthesis.
        int i = 0;
        while (i < chars.length && chars[i] != '(') {
            i++;
        }
        i++; // We stopped on the '('

        // Now iterate, counting the parameter types until we find the closing parenthesis.
        for (; i < chars.length && chars[i] != ')'; i++) {
            switch (chars[i]) {
            // Base types as defined in
            // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3)
            case 'B':
            case 'C':
            case 'D':
            case 'F':
            case 'I':
            case 'J':
            case 'S':
            case 'Z':
                count++;
                break;

            // Array type
            case '[':
                // The array type is defined as "[ ComponentType". This means that we don't want to
                // increment the parameter count yet, as it'll happen in the next iteration through this
                // loop.
                break;

            // Class type
            case 'L':
                count++;
                // Skip forward to the next ";"
                while (chars[i] != ';') {
                    i++;
                }
                break;

            default:
                throw new RuntimeException("Unknown parameter type: " + chars[i]);
            }
        }

        return count;
    }

    @Override
    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        AnnotationMirror mirror = new AnnotationMirror(desc, visible);
        annotations.add(mirror);
        return mirror;
    }

    @Override
    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
        AnnotationMirror mirror = new AnnotationMirror(desc, visible);
        parameterAnnotations[parameter] = mirror;
        return mirror;
    }

    @Override
    public AnnotationVisitor visitAnnotationDefault() {
        annotationDefault = new AnnotationDefaultValueMirror();
        return annotationDefault;
    }

    @Override
    public int compareTo(MethodMirror o) {
        if (this == o) {
            return 0;
        }

        return key.compareTo(o.key);
    }

    public void appendTo(ClassWriter writer) {
        MethodVisitor method = writer.visitMethod(access, name, desc, signature, exceptions);
        for (AnnotationMirror annotation : annotations) {
            annotation.appendTo(method);
        }
        for (int i = 0; i < parameterAnnotations.length; i++) {
            AnnotationMirror annotation = parameterAnnotations[i];
            if (annotation == null) {
                continue;
            }
            annotation.appendTo(method, i);
        }

        if (annotationDefault != null) {
            annotationDefault.appendTo(method);
        }

        method.visitEnd();
    }
}