1 /* 2 * Copyright (C) 2015 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen.base; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkState; 21 22 import com.google.auto.common.MoreTypes; 23 import com.google.auto.value.AutoValue; 24 import com.google.common.base.Equivalence; 25 import dagger.model.Key; 26 import java.util.Map; 27 import javax.lang.model.type.DeclaredType; 28 import javax.lang.model.type.TypeMirror; 29 30 /** 31 * Information about a {@link Map} {@link TypeMirror}. 32 */ 33 @AutoValue 34 public abstract class MapType { 35 /** 36 * The map type itself, wrapped using {@link MoreTypes#equivalence()}. Use 37 * {@link #declaredMapType()} instead. 38 */ wrappedDeclaredMapType()39 protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredMapType(); 40 41 /** 42 * The map type itself. 43 */ declaredMapType()44 private DeclaredType declaredMapType() { 45 return wrappedDeclaredMapType().get(); 46 } 47 48 /** 49 * {@code true} if the map type is the raw {@link Map} type. 50 */ isRawType()51 public boolean isRawType() { 52 return declaredMapType().getTypeArguments().isEmpty(); 53 } 54 55 /** 56 * The map key type. 57 * 58 * @throws IllegalStateException if {@link #isRawType()} is true. 59 */ keyType()60 public TypeMirror keyType() { 61 checkState(!isRawType()); 62 return declaredMapType().getTypeArguments().get(0); 63 } 64 65 /** 66 * The map value type. 67 * 68 * @throws IllegalStateException if {@link #isRawType()} is true. 69 */ valueType()70 public TypeMirror valueType() { 71 checkState(!isRawType()); 72 return declaredMapType().getTypeArguments().get(1); 73 } 74 75 /** 76 * {@code true} if {@link #valueType()} is a {@code clazz}. 77 * 78 * @throws IllegalStateException if {@link #isRawType()} is true. 79 */ valuesAreTypeOf(Class<?> clazz)80 public boolean valuesAreTypeOf(Class<?> clazz) { 81 return MoreTypes.isType(valueType()) && MoreTypes.isTypeOf(clazz, valueType()); 82 } 83 84 /** 85 * Returns {@code true} if the {@linkplain #valueType() value type} of the {@link Map} is a 86 * {@linkplain FrameworkTypes#isFrameworkType(TypeMirror) framework type}. 87 */ valuesAreFrameworkType()88 public boolean valuesAreFrameworkType() { 89 return FrameworkTypes.isFrameworkType(valueType()); 90 } 91 92 /** 93 * {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code 94 * Producer<V>}. 95 * 96 * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a 97 * framework type 98 */ unwrappedFrameworkValueType()99 public TypeMirror unwrappedFrameworkValueType() { 100 checkState( 101 valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", declaredMapType()); 102 return uncheckedUnwrappedValueType(); 103 } 104 105 /** 106 * {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}. 107 * 108 * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a 109 * {@code WrappingClass<V>} 110 * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type 111 * parameter 112 */ unwrappedValueType(Class<?> wrappingClass)113 public TypeMirror unwrappedValueType(Class<?> wrappingClass) { 114 checkArgument( 115 wrappingClass.getTypeParameters().length == 1, 116 "%s must have exactly one type parameter", 117 wrappingClass); 118 checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this); 119 return uncheckedUnwrappedValueType(); 120 } 121 uncheckedUnwrappedValueType()122 private TypeMirror uncheckedUnwrappedValueType() { 123 return MoreTypes.asDeclared(valueType()).getTypeArguments().get(0); 124 } 125 126 /** 127 * {@code true} if {@code type} is a {@link Map} type. 128 */ isMap(TypeMirror type)129 public static boolean isMap(TypeMirror type) { 130 return MoreTypes.isType(type) && MoreTypes.isTypeOf(Map.class, type); 131 } 132 133 /** 134 * {@code true} if {@code key.type()} is a {@link Map} type. 135 */ isMap(Key key)136 public static boolean isMap(Key key) { 137 return isMap(key.type()); 138 } 139 140 /** 141 * Returns a {@link MapType} for {@code type}. 142 * 143 * @throws IllegalArgumentException if {@code type} is not a {@link Map} type 144 */ from(TypeMirror type)145 public static MapType from(TypeMirror type) { 146 checkArgument(isMap(type), "%s is not a Map", type); 147 return new AutoValue_MapType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type))); 148 } 149 150 /** 151 * Returns a {@link MapType} for {@code key}'s {@link Key#type() type}. 152 * 153 * @throws IllegalArgumentException if {@code key.type()} is not a {@link Map} type 154 */ from(Key key)155 public static MapType from(Key key) { 156 return from(key.type()); 157 } 158 } 159