| /* |
| * 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.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; |
| |
| 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; |
| 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 int compareTo(MethodMirror o) { |
| 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); |
| } |
| method.visitEnd(); |
| } |
| } |