001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.core.ext.typeinfo;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.TreeMap;
024:
025: abstract class AbstractMembers {
026:
027: protected final JClassType classType;
028: private JMethod[] cachedOverridableMethods;
029: private final Map<String, JClassType> nestedTypes = new HashMap<String, JClassType>();
030:
031: public AbstractMembers(JClassType classType) {
032: this .classType = classType;
033: }
034:
035: public JConstructor findConstructor(JType[] paramTypes) {
036: JConstructor[] ctors = getConstructors();
037: for (int i = 0; i < ctors.length; i++) {
038: JConstructor candidate = ctors[i];
039: if (candidate.hasParamTypes(paramTypes)) {
040: return candidate;
041: }
042: }
043: return null;
044: }
045:
046: public JField findField(String name) {
047: return doGetFields().get(name);
048: }
049:
050: public JMethod findMethod(String name, JType[] paramTypes) {
051: JMethod[] overloads = getOverloads(name);
052: for (int i = 0; i < overloads.length; i++) {
053: JMethod candidate = overloads[i];
054: if (candidate.hasParamTypes(paramTypes)) {
055: return candidate;
056: }
057: }
058: return null;
059: }
060:
061: public JClassType findNestedType(String typeName) {
062: String[] parts = typeName.split("\\.");
063: return findNestedTypeImpl(parts, 0);
064: }
065:
066: public JConstructor getConstructor(JType[] paramTypes)
067: throws NotFoundException {
068: JConstructor result = findConstructor(paramTypes);
069: if (result == null) {
070: throw new NotFoundException();
071: }
072: return result;
073: }
074:
075: public JConstructor[] getConstructors() {
076: return doGetConstructors().toArray(TypeOracle.NO_JCTORS);
077: }
078:
079: public JField getField(String name) {
080: JField field = findField(name);
081: assert (field != null);
082: return field;
083: }
084:
085: public JField[] getFields() {
086: return doGetFields().values().toArray(TypeOracle.NO_JFIELDS);
087: }
088:
089: public JMethod getMethod(String name, JType[] paramTypes)
090: throws NotFoundException {
091: JMethod result = findMethod(name, paramTypes);
092: if (result == null) {
093: throw new NotFoundException();
094: }
095: return result;
096: }
097:
098: public JMethod[] getMethods() {
099: List<JMethod> resultMethods = new ArrayList<JMethod>();
100: for (List<JMethod> overloads : doGetMethods().values()) {
101: resultMethods.addAll(overloads);
102: }
103: return resultMethods.toArray(TypeOracle.NO_JMETHODS);
104: }
105:
106: public JClassType getNestedType(String typeName)
107: throws NotFoundException {
108: JClassType result = findNestedType(typeName);
109: if (result == null) {
110: throw new NotFoundException();
111: }
112: return result;
113: }
114:
115: public JClassType[] getNestedTypes() {
116: return nestedTypes.values().toArray(TypeOracle.NO_JCLASSES);
117: }
118:
119: public JMethod[] getOverloads(String name) {
120: List<?> resultMethods = doGetMethods().get(name);
121: if (resultMethods != null) {
122: return resultMethods.toArray(TypeOracle.NO_JMETHODS);
123: } else {
124: return TypeOracle.NO_JMETHODS;
125: }
126: }
127:
128: public JMethod[] getOverridableMethods() {
129: if (cachedOverridableMethods == null) {
130: Map<String, JMethod> methodsBySignature = new TreeMap<String, JMethod>();
131: getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature);
132: if (classType.isClass() != null) {
133: getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature);
134: }
135: int size = methodsBySignature.size();
136: Collection<JMethod> leafMethods = methodsBySignature
137: .values();
138: cachedOverridableMethods = leafMethods
139: .toArray(new JMethod[size]);
140: }
141: return cachedOverridableMethods;
142: }
143:
144: protected void addConstructor(JConstructor ctor) {
145: assert (!doGetConstructors().contains(ctor));
146: doGetConstructors().add(ctor);
147: }
148:
149: protected void addField(JField field) {
150: Object existing = doGetFields().put(field.getName(), field);
151: assert (existing == null);
152: }
153:
154: protected void addMethod(JMethod method) {
155: String methodName = method.getName();
156: Map<String, List<JMethod>> methods = doGetMethods();
157: List<JMethod> overloads = methods.get(methodName);
158: if (overloads == null) {
159: overloads = new ArrayList<JMethod>();
160: methods.put(methodName, overloads);
161: }
162: overloads.add(method);
163: }
164:
165: protected void addNestedType(JClassType type) {
166: nestedTypes.put(type.getSimpleSourceName(), type);
167: }
168:
169: protected abstract List<JConstructor> doGetConstructors();
170:
171: protected abstract Map<String, JField> doGetFields();
172:
173: protected abstract Map<String, List<JMethod>> doGetMethods();
174:
175: protected JClassType findNestedTypeImpl(String[] typeName, int index) {
176: JClassType found = nestedTypes.get(typeName[index]);
177: if (found == null) {
178: return null;
179: } else if (index < typeName.length - 1) {
180: return found.findNestedTypeImpl(typeName, index + 1);
181: } else {
182: return found;
183: }
184: }
185:
186: protected void getOverridableMethodsOnSuperclassesAndThisClass(
187: Map<String, JMethod> methodsBySignature) {
188: assert (classType.isClass() != null);
189:
190: // Recurse first so that more derived methods will clobber less derived
191: // methods.
192: JClassType super Class = classType.getSuperclass();
193: if (super Class != null) {
194: super Class
195: .getOverridableMethodsOnSuperclassesAndThisClass(methodsBySignature);
196: }
197:
198: JMethod[] declaredMethods = getMethods();
199: for (int i = 0; i < declaredMethods.length; i++) {
200: JMethod method = declaredMethods[i];
201:
202: // Ensure that this method is overridable.
203: if (method.isFinal() || method.isPrivate()
204: || method.isStatic()) {
205: // We cannot override this method, so skip it.
206: continue;
207: }
208:
209: // We can override this method, so record it.
210: String sig = computeInternalSignature(method);
211: methodsBySignature.put(sig, method);
212: }
213: }
214:
215: /**
216: * Gets the methods declared in interfaces that this type extends. If this
217: * type is a class, its own methods are not added. If this type is an
218: * interface, its own methods are added. Used internally by
219: * {@link #getOverridableMethods()}.
220: *
221: * @param methodsBySignature
222: */
223: protected void getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(
224: Map<String, JMethod> methodsBySignature) {
225: // Recurse first so that more derived methods will clobber less derived
226: // methods.
227: JClassType[] super Intfs = classType.getImplementedInterfaces();
228: for (int i = 0; i < super Intfs.length; i++) {
229: JClassType super Intf = super Intfs[i];
230: super Intf
231: .getOverridableMethodsOnSuperinterfacesAndMaybeThisInterface(methodsBySignature);
232: }
233:
234: if (classType.isInterface() == null) {
235: // This is not an interface, so we're done after having visited its
236: // implemented interfaces.
237: return;
238: }
239:
240: JMethod[] declaredMethods = getMethods();
241: for (int i = 0; i < declaredMethods.length; i++) {
242: JMethod method = declaredMethods[i];
243:
244: String sig = computeInternalSignature(method);
245: JMethod existing = methodsBySignature.get(sig);
246: if (existing != null) {
247: JClassType existingType = existing.getEnclosingType();
248: JClassType this Type = method.getEnclosingType();
249: if (this Type.isAssignableFrom(existingType)) {
250: // The existing method is in a more-derived type, so don't replace it.
251: continue;
252: }
253: }
254: methodsBySignature.put(sig, method);
255: }
256: }
257:
258: protected JClassType getParentType() {
259: return classType;
260: }
261:
262: private String computeInternalSignature(JMethod method) {
263: StringBuffer sb = new StringBuffer();
264: sb.setLength(0);
265: sb.append(method.getName());
266: JParameter[] params = method.getParameters();
267: for (int j = 0; j < params.length; j++) {
268: JParameter param = params[j];
269: sb.append("/");
270: sb.append(param.getType().getErasedType()
271: .getQualifiedSourceName());
272: }
273: return sb.toString();
274: }
275:
276: }
|