| /* |
| * Copyright 2007 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.core.ext.typeinfo.NotFoundException; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| abstract class AbstractMembers { |
| |
| protected final JClassType classType; |
| private JMethod[] cachedInheritableMethods; |
| private JMethod[] cachedOverridableMethods; |
| |
| public AbstractMembers(JClassType classType) { |
| this.classType = classType; |
| } |
| |
| public JConstructor findConstructor(JType[] paramTypes) { |
| JConstructor[] ctors = getConstructors(); |
| for (JConstructor candidate : ctors) { |
| if (candidate.hasParamTypes(paramTypes)) { |
| return candidate; |
| } |
| } |
| return null; |
| } |
| |
| public abstract JField findField(String name); |
| |
| public JMethod findMethod(String name, JType[] paramTypes) { |
| JMethod[] overloads = getOverloads(name); |
| for (JMethod candidate : overloads) { |
| if (candidate.hasParamTypes(paramTypes)) { |
| return candidate; |
| } |
| } |
| return null; |
| } |
| |
| public JClassType findNestedType(String typeName) { |
| String[] parts = typeName.split("\\."); |
| return findNestedTypeImpl(parts, 0); |
| } |
| |
| public JConstructor getConstructor(JType[] paramTypes) |
| throws NotFoundException { |
| JConstructor result = findConstructor(paramTypes); |
| if (result == null) { |
| throw new NotFoundException(); |
| } |
| return result; |
| } |
| |
| public JConstructor[] getConstructors() { |
| return doGetConstructors().toArray(TypeOracle.NO_JCTORS); |
| } |
| |
| public JField getField(String name) { |
| JField field = findField(name); |
| assert (field != null); |
| return field; |
| } |
| |
| public abstract JField[] getFields(); |
| |
| public JMethod[] getInheritableMethods() { |
| if (cachedInheritableMethods == null) { |
| Map<String, JMethod> methodsBySignature = new TreeMap<String, JMethod>(); |
| getInheritableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); |
| if (classType.isClass() != null) { |
| getInheritableMethodsOnSuperclassesAndThisClass(methodsBySignature); |
| } |
| int size = methodsBySignature.size(); |
| if (size == 0) { |
| cachedInheritableMethods = TypeOracle.NO_JMETHODS; |
| } else { |
| Collection<JMethod> leafMethods = methodsBySignature.values(); |
| cachedInheritableMethods = leafMethods.toArray(new JMethod[size]); |
| } |
| } |
| return cachedInheritableMethods; |
| } |
| |
| public JMethod getMethod(String name, JType[] paramTypes) |
| throws NotFoundException { |
| JMethod result = findMethod(name, paramTypes); |
| if (result == null) { |
| throw new NotFoundException(); |
| } |
| return result; |
| } |
| |
| public abstract JMethod[] getMethods(); |
| |
| public JClassType getNestedType(String typeName) throws NotFoundException { |
| JClassType result = findNestedType(typeName); |
| if (result == null) { |
| throw new NotFoundException(); |
| } |
| return result; |
| } |
| |
| public JClassType[] getNestedTypes() { |
| return doGetNestedTypes().values().toArray(TypeOracle.NO_JCLASSES); |
| } |
| |
| public abstract JMethod[] getOverloads(String name); |
| |
| public JMethod[] getOverridableMethods() { |
| if (cachedOverridableMethods == null) { |
| JMethod[] inheritableMethods = getInheritableMethods(); |
| ArrayList<JMethod> methods = new ArrayList<JMethod>( |
| inheritableMethods.length); |
| for (JMethod method : inheritableMethods) { |
| if (!method.isFinal()) { |
| methods.add(method); |
| } |
| } |
| int size = methods.size(); |
| if (size == 0) { |
| cachedOverridableMethods = TypeOracle.NO_JMETHODS; |
| } else { |
| cachedOverridableMethods = methods.toArray(new JMethod[size]); |
| } |
| } |
| return cachedOverridableMethods; |
| } |
| |
| protected abstract void addConstructor(JConstructor ctor); |
| |
| protected abstract void addField(JField field); |
| |
| protected abstract void addMethod(JMethod method); |
| |
| protected abstract List<JConstructor> doGetConstructors(); |
| |
| protected abstract Map<String, JClassType> doGetNestedTypes(); |
| |
| protected JClassType findNestedTypeImpl(String[] typeName, int index) { |
| JClassType found = doGetNestedTypes().get(typeName[index]); |
| if (found == null) { |
| return null; |
| } else if (index < typeName.length - 1) { |
| return found.findNestedTypeImpl(typeName, index + 1); |
| } else { |
| return found; |
| } |
| } |
| |
| protected void getInheritableMethodsOnSuperclassesAndThisClass( |
| Map<String, JMethod> methodsBySignature) { |
| assert (classType.isClass() != null); |
| |
| // Recurse first so that more derived methods will clobber less derived |
| // methods. |
| JClassType superClass = classType.getSuperclass(); |
| if (superClass != null) { |
| superClass.getInheritableMethodsOnSuperclassesAndThisClass(methodsBySignature); |
| } |
| |
| JMethod[] declaredMethods = getMethods(); |
| for (JMethod method : declaredMethods) { |
| // Ensure that this method is inheritable. |
| if (method.isPrivate() || method.isStatic()) { |
| // We cannot inherit this method, so skip it. |
| continue; |
| } |
| |
| // We can override this method, so record it. |
| String sig = computeInternalSignature(method); |
| methodsBySignature.put(sig, method); |
| } |
| } |
| |
| /** |
| * Gets the methods declared in interfaces that this type extends. If this |
| * type is a class, its own methods are not added. If this type is an |
| * interface, its own methods are added. Used internally by |
| * {@link #getOverridableMethods()}. |
| * |
| * @param methodsBySignature |
| */ |
| protected void getInheritableMethodsOnSuperinterfacesAndMaybeThisInterface( |
| Map<String, JMethod> methodsBySignature) { |
| // Recurse first so that more derived methods will clobber less derived |
| // methods. |
| JClassType[] superIntfs = classType.getImplementedInterfaces(); |
| for (JClassType superIntf : superIntfs) { |
| superIntf.getInheritableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature); |
| } |
| |
| if (classType.isInterface() == null) { |
| // This is not an interface, so we're done after having visited its |
| // implemented interfaces. |
| return; |
| } |
| |
| JMethod[] declaredMethods = getMethods(); |
| for (JMethod method : declaredMethods) { |
| String sig = computeInternalSignature(method); |
| JMethod existing = methodsBySignature.get(sig); |
| if (existing != null) { |
| JClassType existingType = existing.getEnclosingType(); |
| JClassType thisType = method.getEnclosingType(); |
| if (thisType.isAssignableFrom(existingType)) { |
| // The existing method is in a more-derived type, so don't replace it. |
| continue; |
| } |
| } |
| methodsBySignature.put(sig, method); |
| } |
| } |
| |
| protected JClassType getParentType() { |
| return classType; |
| } |
| |
| private String computeInternalSignature(JMethod method) { |
| StringBuilder sb = new StringBuilder(); |
| sb.setLength(0); |
| sb.append(method.getName()); |
| JParameter[] params = method.getParameters(); |
| for (JParameter param : params) { |
| sb.append("/"); |
| sb.append(param.getType().getErasedType().getQualifiedSourceName()); |
| } |
| return sb.toString(); |
| } |
| |
| } |