/* * 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.user.rebind.rpc; import com.google.gwt.core.ext.typeinfo.JArrayType; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JGenericType; import com.google.gwt.core.ext.typeinfo.JParameterizedType; import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JRawType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.JWildcardType; /** * <p> * This visitor supports transforming interior parts of a type. Subclasses * should override the appropriate <code>endVisit</code> methods and, when such * a method wants to replace its argument, assign the replacement to the field * {@link #replacement}. * </p> * * <p> * Any specified replacements must be sensible no matter what context they might * be used in. Specifically: * </p> * <ul> * <li>Primitive types may only be replaced by primitive types. * <li>Reference types may only be replaced by reference types. * <li>Generic types may only be replaced by generic types, and the replacement * should have the same number of type parameters as the original. * </ul> */ class JModTypeVisitor extends JTypeVisitor { /** * A subclass's <code>endVisit</code> method can indicate that it wants to * replace its argument by assigning the replacement to this field. */ protected JType replacement; @Override public void accept(JType type) { replacement = type; acceptChildren(type); endVisit(replacement); } public JClassType transform(JClassType type) { // transforming a class type should give a class type back return (JClassType) transform((JType) type); } public JGenericType transform(JGenericType type) { // transforming a generic type should give a generic type back return (JGenericType) transform((JType) type); } public JPrimitiveType transform(JPrimitiveType type) { // transforming a primitive type should give a primitive type back return (JPrimitiveType) transform((JType) type); } public JType transform(JType type) { accept(type); return replacement; } /** * Do the same thing as {@link JTypeVisitor#acceptChildren(JType)}, but if any * children types are replaced, reconstruct a version of <code>type</code> * that has those corresponding replacements made and assign the new type to * {@link #replacement}. */ @Override protected void acceptChildren(JType type) { JArrayType typeArray = type.isArray(); if (typeArray != null) { JType oldComponentType = typeArray.getComponentType(); JType newComponentType = transform(oldComponentType); if (oldComponentType == newComponentType) { replacement = type; } else { replacement = typeArray.getOracle().getArrayType(newComponentType); } } JParameterizedType typeParameterized = type.isParameterized(); if (typeParameterized != null) { JGenericType oldBaseType = typeParameterized.getBaseType(); JGenericType newBaseType = transform(oldBaseType); JClassType oldEnclosingType = typeParameterized.getEnclosingType(); JClassType newEnclosingType = oldEnclosingType == null ? null : transform(oldEnclosingType); JClassType[] oldTypeArgs = typeParameterized.getTypeArgs(); JClassType[] newTypeArgs = new JClassType[oldTypeArgs.length]; boolean argsAllSame = true; for (int i = 0; i < oldTypeArgs.length; i++) { newTypeArgs[i] = transform(oldTypeArgs[i]); if (newTypeArgs[i] != oldTypeArgs[i]) { argsAllSame = false; } } if (argsAllSame && oldBaseType == newBaseType && oldEnclosingType == newEnclosingType) { replacement = type; } else { replacement = typeParameterized.getOracle().getParameterizedType(newBaseType, newEnclosingType, newTypeArgs); } } JRawType typeRaw = type.isRawType(); if (typeRaw != null) { JGenericType oldBaseType = typeRaw.getBaseType(); JGenericType newBaseType = transform(oldBaseType); if (oldBaseType == newBaseType) { replacement = type; } else { replacement = newBaseType.getRawType(); } } JWildcardType typeWild = type.isWildcard(); if (typeWild != null) { JClassType oldBound = typeWild.getFirstBound(); JClassType newBound = transform(oldBound); if (oldBound == newBound) { replacement = type; } else { replacement = typeWild.getOracle().getWildcardType(typeWild.getBoundType(), newBound); } } } }