/* * 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.core.ext.TreeLogger; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.dev.asm.Type; import com.google.gwt.dev.asm.signature.SignatureVisitor; import com.google.gwt.dev.javac.MethodArgNamesLookup; import com.google.gwt.dev.javac.Resolver; import com.google.gwt.dev.javac.TypeParameterLookup; import com.google.gwt.dev.javac.typemodel.JAbstractMethod; import com.google.gwt.dev.javac.typemodel.JClassType; import com.google.gwt.dev.javac.typemodel.JTypeParameter; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Resolve a method given its generic signature, including return type, * parameter types, and exceptions thrown. */ public class ResolveMethodSignature extends EmptySignatureVisitor { private final MethodArgNamesLookup allMethodArgs; private final String[] argNames; private final boolean argNamesAreReal; private final Type[] argTypes; private ArrayList<JType[]> bounds = null; private JTypeParameter currentParam = null; private final List<JClassType[]> exceptions = new ArrayList<JClassType[]>(); private final boolean hasReturnType; private final TreeLogger logger; private final JAbstractMethod method; private final CollectMethodData methodData; private final List<JType[]> params = new ArrayList<JType[]>(); private final Resolver resolver; private final JType[] returnType = new JType[1]; private final TypeParameterLookup typeParamLookup; /** * Resolve a method signature. * * @param resolver * @param logger * @param method * @param typeParamLookup * @param hasReturnType * @param methodData * @param argTypes * @param argNames * @param argNamesAreReal * @param allMethodArgs */ public ResolveMethodSignature(Resolver resolver, TreeLogger logger, JAbstractMethod method, TypeParameterLookup typeParamLookup, boolean hasReturnType, CollectMethodData methodData, Type[] argTypes, String[] argNames, boolean argNamesAreReal, MethodArgNamesLookup allMethodArgs) { this.resolver = resolver; this.logger = logger; this.method = method; this.typeParamLookup = typeParamLookup; this.hasReturnType = hasReturnType; this.methodData = methodData; this.argTypes = argTypes; this.argNames = argNames; this.argNamesAreReal = argNamesAreReal; this.allMethodArgs = allMethodArgs; } /** * @return true if resolution succeeded. */ public boolean finish() { boolean failed = false; finishBound(); // Set return type if (hasReturnType) { failed |= (returnType[0] == null); resolver.setReturnType(method, returnType[0]); } // Create arguments List<CollectAnnotationData>[] argAnnotations = methodData.getArgAnnotations(); if (argTypes.length != params.size()) { // TODO(jat): remove this check throw new IllegalStateException( "Arg count mismatch between method descriptor (" + methodData.getDesc() + ") and signature (" + methodData.getSignature() + ")"); } String[] names = argNames; boolean namesAreReal = argNamesAreReal; if (!namesAreReal) { // lookup argument names in allMethodArgs String[] lookupArgNames = allMethodArgs.lookup(method, methodData); if (lookupArgNames != null) { names = lookupArgNames; namesAreReal = true; } } for (int i = 0; i < argTypes.length; ++i) { JType argType = params.get(i)[0]; if (argType == null) { failed = true; continue; } // Try to resolve annotations, ignore any that fail. Map<Class<? extends Annotation>, Annotation> declaredAnnotations = new HashMap<Class<? extends Annotation>, Annotation>(); resolver.resolveAnnotations(logger, argAnnotations[i], declaredAnnotations); // JParameter adds itself to the method resolver.newParameter(method, argType, names[i], declaredAnnotations, namesAreReal); } // Handle thrown exceptions for (JClassType[] exc : exceptions) { if (exc[0] == null) { failed = true; continue; } resolver.addThrows(method, exc[0]); } return !failed; } @Override public SignatureVisitor visitArrayType() { assert false : "visitArrayType called on ResolveClassTypeVariables"; return null; } @Override public SignatureVisitor visitClassBound() { JType[] bound = new JClassType[1]; bounds.add(bound); return new ResolveTypeSignature(resolver, resolver.getBinaryMapper(), logger, bound, typeParamLookup, null); } @Override public SignatureVisitor visitExceptionType() { JClassType[] exc = new JClassType[1]; exceptions.add(exc); return new ResolveTypeSignature(resolver, resolver.getBinaryMapper(), logger, exc, typeParamLookup, null); } @Override public void visitFormalTypeParameter(String name) { finishBound(); currentParam = typeParamLookup.lookup(name); bounds = new ArrayList<JType[]>(); } @Override public SignatureVisitor visitInterfaceBound() { JType[] bound = new JType[1]; bounds.add(bound); return new ResolveTypeSignature(resolver, resolver.getBinaryMapper(), logger, bound, typeParamLookup, null); } @Override public SignatureVisitor visitParameterType() { JType[] param = new JType[1]; params.add(param); return new ResolveTypeSignature(resolver, resolver.getBinaryMapper(), logger, param, typeParamLookup, null); } @Override public SignatureVisitor visitReturnType() { return new ResolveTypeSignature(resolver, resolver.getBinaryMapper(), logger, returnType, typeParamLookup, null); } private void finishBound() { if (currentParam != null) { int n = bounds.size(); JClassType[] boundTypes = new JClassType[n]; for (int i = 0; i < n; ++i) { boundTypes[i] = (JClassType) bounds.get(i)[0]; } currentParam.setBounds(boundTypes); currentParam = null; // TODO(jat): remove after debugging phase bounds = null; } } }