blob: 9ebeabef9af3934d3648fb7790c2b64e41853b97 [file] [log] [blame]
/*
* 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);
}
}
}
}