| /* |
| * Copyright 2011 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.web.bindery.requestfactory.apt; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import javax.lang.model.element.TypeElement; |
| import javax.lang.model.type.DeclaredType; |
| import javax.lang.model.type.NoType; |
| import javax.lang.model.type.PrimitiveType; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.type.TypeVariable; |
| import javax.lang.model.type.WildcardType; |
| import javax.lang.model.util.SimpleTypeVisitor6; |
| |
| /** |
| * Utility type for reducing complex type declarations to ones suitable for |
| * determining assignability based on RequestFactory's type-mapping semantics. |
| * <p> |
| * Rules: |
| * <ul> |
| * <li>primitive type {@code ->} boxed type (optional)</li> |
| * <li>{@code void -> Void} (optional)</li> |
| * <li>{@code <T extends Foo> -> Foo}</li> |
| * <li>{@code ? extends Foo -> Foo}</li> |
| * <li>{@code Foo<complex type> -> Foo<simplified type>}</li> |
| * </ul> |
| */ |
| public class TypeSimplifier extends SimpleTypeVisitor6<TypeMirror, State> { |
| |
| public static TypeMirror simplify(TypeMirror toBox, boolean boxPrimitives, State state) { |
| if (toBox == null) { |
| return null; |
| } |
| return toBox.accept(new TypeSimplifier(boxPrimitives), state); |
| } |
| |
| private final boolean boxPrimitives; |
| |
| private TypeSimplifier(boolean boxPrimitives) { |
| this.boxPrimitives = boxPrimitives; |
| } |
| |
| @Override |
| public TypeMirror visitDeclared(DeclaredType x, State state) { |
| if (x.getTypeArguments().isEmpty()) { |
| return x; |
| } |
| List<TypeMirror> newArgs = new ArrayList<TypeMirror>(x.getTypeArguments().size()); |
| for (TypeMirror original : x.getTypeArguments()) { |
| // Are we looking at a self-parameterized type like Foo<T extends Foo<T>>? |
| if (original.getKind().equals(TypeKind.TYPEVAR) && state.types.isAssignable(original, x)) { |
| // If so, return a raw type |
| return state.types.getDeclaredType((TypeElement) x.asElement()); |
| } else { |
| newArgs.add(original.accept(this, state)); |
| } |
| } |
| return state.types.getDeclaredType((TypeElement) x.asElement(), newArgs |
| .toArray(new TypeMirror[newArgs.size()])); |
| } |
| |
| @Override |
| public TypeMirror visitNoType(NoType x, State state) { |
| if (boxPrimitives) { |
| return state.findType(Void.class); |
| } |
| return x; |
| } |
| |
| @Override |
| public TypeMirror visitPrimitive(PrimitiveType x, State state) { |
| if (boxPrimitives) { |
| return state.types.boxedClass(x).asType(); |
| } |
| return x; |
| } |
| |
| @Override |
| public TypeMirror visitTypeVariable(TypeVariable x, State state) { |
| if (x.equals(x.getUpperBound())) { |
| // See comment in TransportableTypeVisitor |
| return state.types.erasure(x); |
| } |
| return x.getUpperBound().accept(this, state); |
| } |
| |
| @Override |
| public TypeMirror visitWildcard(WildcardType x, State state) { |
| // The JLS doesn't define erasure for wildcards [1], so don't rely on |
| // javac's implementation. Instead, simplify wildcards as: |
| // ? extends Foo -> erasure(Foo) |
| // and: ? -> Object |
| // |
| // [1] https://bugs.openjdk.java.net/browse/JDK-8055054 |
| return x.getExtendsBound() != null |
| ? x.getExtendsBound().accept(this, state) |
| : state.findType(Object.class); |
| } |
| |
| @Override |
| protected TypeMirror defaultAction(TypeMirror x, State state) { |
| return state.types.getNoType(TypeKind.NONE); |
| } |
| } |