| /* |
| * Copyright 2008 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.typemodel; |
| |
| import com.google.gwt.core.ext.typeinfo.JType; |
| import com.google.gwt.dev.util.collect.HashMap; |
| import com.google.gwt.dev.util.collect.Lists; |
| import com.google.gwt.dev.util.collect.Maps; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Class that initializes the different members of a |
| * {@link JDelegatingClassType} from its corresponding base type on demand. |
| */ |
| class DelegateMembers extends AbstractMembers { |
| /** |
| * Implementation note: it is critical that everything in this class is |
| * computed as lazily as possible. Many, many more parameterized types, raw |
| * types, type bindings, or wilcard types can be created than real classes, |
| * and computing anything up front would add runtime overhead and memory. |
| */ |
| |
| private final JClassType baseType; |
| private Map<String, JField> fieldMap; |
| private JField[] fields; |
| private List<JConstructor> lazyConstructors; |
| private Map<String, Object> methodMap; |
| private JMethod[] methods; |
| private final Substitution substitution; |
| |
| /** |
| */ |
| public DelegateMembers(JDelegatingClassType enclosingType, |
| JClassType baseType, Substitution substitution) { |
| super(enclosingType); |
| this.baseType = baseType; |
| this.substitution = substitution; |
| } |
| |
| @Override |
| public JField findField(String name) { |
| initFields(); |
| return fieldMap.get(name); |
| } |
| |
| @Override |
| public JField[] getFields() { |
| initFields(); |
| return fields.length == 0 ? fields : fields.clone(); |
| } |
| |
| @Override |
| public JMethod[] getMethods() { |
| initMethods(); |
| return methods.length == 0 ? methods : methods.clone(); |
| } |
| |
| @Override |
| public JMethod[] getOverloads(String name) { |
| initMethods(); |
| Object object = methodMap.get(name); |
| if (object == null) { |
| return TypeOracle.NO_JMETHODS; |
| } else if (object instanceof JMethod) { |
| return new JMethod[]{(JMethod) object}; |
| } else { |
| return ((JMethod[]) object).clone(); |
| } |
| } |
| |
| @Override |
| protected void addConstructor(JConstructor ctor) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| protected void addField(JField field) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| protected void addMethod(JMethod method) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| protected List<JConstructor> doGetConstructors() { |
| if (lazyConstructors != null) { |
| /* |
| * Return if the constructors are being initialized or have been |
| * initialized. |
| */ |
| return lazyConstructors; |
| } |
| lazyConstructors = new ArrayList<JConstructor>(); |
| |
| JConstructor[] baseCtors = baseType.getConstructors(); |
| for (JConstructor baseCtor : baseCtors) { |
| JConstructor newCtor = new JConstructor(getParentType(), baseCtor); |
| initializeParams(baseCtor, newCtor); |
| lazyConstructors.add(newCtor); |
| } |
| |
| return lazyConstructors = Lists.normalize(lazyConstructors); |
| } |
| |
| @Override |
| protected Map<String, JClassType> doGetNestedTypes() { |
| // TODO: is this correct? |
| return Maps.create(); |
| } |
| |
| private void initFields() { |
| if (fields != null) { |
| return; |
| } |
| // Transitively sorted. |
| fields = baseType.getFields(); |
| fieldMap = new HashMap<String, JField>(); |
| for (int i = 0; i < fields.length; ++i) { |
| JField baseField = fields[i]; |
| JField newField = new JField(getParentType(), baseField); |
| newField.setType(substitute(baseField.getType())); |
| fields[i] = newField; |
| fieldMap.put(newField.getName(), newField); |
| } |
| fieldMap = Maps.normalize(fieldMap); |
| } |
| |
| private void initializeExceptions(JAbstractMethod srcMethod, |
| JAbstractMethod newMethod) { |
| for (JClassType thrown : srcMethod.getThrows()) { |
| // exceptions cannot be parameterized; just copy them over |
| newMethod.addThrows(thrown); |
| } |
| } |
| |
| private void initializeParams(JAbstractMethod srcMethod, |
| JAbstractMethod newMethod) { |
| for (JParameter srcParam : srcMethod.getParameters()) { |
| JParameter newParam = new JParameter(newMethod, srcParam); |
| newParam.setType(substitute(srcParam.getType())); |
| newMethod.addParameter(newParam); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private void initMethods() { |
| if (methods != null) { |
| return; |
| } |
| // Transitively sorted. |
| methods = baseType.getMethods(); |
| methodMap = new HashMap<String, Object>(); |
| for (int i = 0; i < methods.length; ++i) { |
| JMethod baseMethod = methods[i]; |
| JMethod newMethod = new JMethod(getParentType(), baseMethod); |
| initializeParams(baseMethod, newMethod); |
| newMethod.setReturnType(substitute(baseMethod.getReturnType())); |
| initializeExceptions(baseMethod, newMethod); |
| methods[i] = newMethod; |
| |
| String methodName = newMethod.getName(); |
| Object object = methodMap.get(methodName); |
| if (object == null) { |
| methodMap.put(methodName, newMethod); |
| } else if (object instanceof JMethod) { |
| List<JMethod> list = new ArrayList<JMethod>(2); |
| list.add((JMethod) object); |
| list.add(newMethod); |
| methodMap.put(methodName, list); |
| } else { |
| List<JMethod> list = (List<JMethod>) object; |
| list.add(newMethod); |
| } |
| } |
| |
| // Replace the ArrayLists with plain arrays. |
| for (String methodName : methodMap.keySet()) { |
| Object object = methodMap.get(methodName); |
| if (object instanceof List) { |
| List<JMethod> list = (List<JMethod>) object; |
| methodMap.put(methodName, list.toArray(TypeOracle.NO_JMETHODS)); |
| } |
| } |
| methodMap = Maps.normalize(methodMap); |
| } |
| |
| private JType substitute(JType type) { |
| if (type instanceof JClassType) { |
| return substitution.getSubstitution((JClassType) type); |
| } |
| return type; |
| } |
| } |