blob: 1f0511bf81800613da1d65ec73638d50a8351468 [file] [log] [blame]
/*
* Copyright 2009 Google 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.google.gwt.dev.javac.asm;
import com.google.gwt.dev.asm.AnnotationVisitor;
import com.google.gwt.dev.asm.Label;
import com.google.gwt.dev.asm.Opcodes;
import com.google.gwt.dev.asm.Type;
import com.google.gwt.dev.asm.commons.EmptyVisitor;
import java.util.ArrayList;
import java.util.List;
/**
* Collects data from a single method.
*/
public class CollectMethodData extends EmptyVisitor {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final List<CollectAnnotationData> annotations = new ArrayList<CollectAnnotationData>();
private final String name;
private final String desc;
private final String signature;
private final String[] exceptions;
private Type[] argTypes;
private final String[] argNames;
private final List<CollectAnnotationData>[] paramAnnots;
private boolean actualArgNames = false;
private final int access;
private int syntheticArgs;
/**
* Prepare to collect data for a method from bytecode.
*
* @param classType
* @param access
* @param name
* @param desc
* @param signature
* @param exceptions
*/
@SuppressWarnings("unchecked")
// for new List[]
public CollectMethodData(CollectClassData.ClassType classType, int access,
String name, String desc, String signature, String[] exceptions) {
this.access = access;
this.name = name;
this.desc = desc;
this.signature = signature;
this.exceptions = exceptions;
syntheticArgs = 0;
argTypes = Type.getArgumentTypes(desc);
// Non-static instance methods and constructors of non-static inner
// classes have an extra synthetic parameter that isn't in the source,
// so we remove it. Note that for local classes, they may or may not
// have this synthetic parameter depending on whether the containing
// method is static, but we can't get that info here. However, since
// local classes are dropped from TypeOracle, we don't care.
if (classType.hasHiddenConstructorArg() && "<init>".equals(name)) {
// remove "this$1" as a parameter
if (argTypes.length < 1) {
throw new IllegalStateException(
"Missing synthetic argument in constructor");
}
syntheticArgs = 1;
int n = argTypes.length - syntheticArgs;
Type[] newArgTypes = new Type[n];
System.arraycopy(argTypes, syntheticArgs, newArgTypes, 0, n);
argTypes = newArgTypes;
}
argNames = new String[argTypes.length];
paramAnnots = new List[argTypes.length];
for (int i = 0; i < argNames.length; ++i) {
argNames[i] = "arg" + i;
paramAnnots[i] = new ArrayList<CollectAnnotationData>();
}
if (argNames.length == 0) {
// save some work later if there aren't any parameters
actualArgNames = true;
}
}
/**
* @return the access
*/
public int getAccess() {
return access;
}
/**
* @return the annotations
*/
public List<CollectAnnotationData> getAnnotations() {
return annotations;
}
public List<CollectAnnotationData>[] getArgAnnotations() {
return paramAnnots;
}
/**
* @return the argNames
*/
public String[] getArgNames() {
return argNames;
}
/**
* @return the argTypes
*/
public Type[] getArgTypes() {
return argTypes;
}
/**
* @return the desc
*/
public String getDesc() {
return desc;
}
/**
* @return the exceptions
*/
public String[] getExceptions() {
return exceptions == null ? EMPTY_STRING_ARRAY : exceptions;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the signature
*/
public String getSignature() {
return signature;
}
/**
* @return the actualArgNames
*/
public boolean hasActualArgNames() {
return actualArgNames;
}
@Override
public String toString() {
return "method " + name;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
CollectAnnotationData av = new CollectAnnotationData(desc, visible);
annotations.add(av);
return av;
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
if ((access & Opcodes.ACC_STATIC) == 0) {
// adjust for "this"
// TODO(jat): do we need to account for this$0 in inner classes?
--index;
}
// TODO(jat): is it safe to assume parameter slots don't get reused?
// Do we need to check if the name has already been assigned?
if (index >= 0 && index < argNames.length) {
actualArgNames = true;
argNames[index] = name;
}
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
boolean visible) {
CollectAnnotationData av = new CollectAnnotationData(desc, visible);
if (parameter >= syntheticArgs) {
// javac adds @Synthetic annotation on its synthetic constructor
// arg, so we ignore it since it isn't in the source.
paramAnnots[parameter - syntheticArgs].add(av);
}
return av;
}
}