blob: 2c3e9c0544c311fb9547b80881bec7afbfa93fa2 [file] [log] [blame]
/*
* 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();
}
}