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 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf; 22 import static dagger.internal.codegen.xprocessing.XTypes.unwrapType; 23 24 import androidx.room.compiler.processing.XType; 25 import com.google.auto.value.AutoValue; 26 import com.squareup.javapoet.ClassName; 27 import com.squareup.javapoet.TypeName; 28 import dagger.internal.codegen.javapoet.TypeNames; 29 import dagger.internal.codegen.model.Key; 30 import dagger.internal.codegen.xprocessing.XTypes; 31 32 /** Information about a {@link java.util.Map} type. */ 33 @AutoValue 34 public abstract class MapType { 35 private XType type; 36 37 /** The map type itself. */ typeName()38 abstract TypeName typeName(); 39 40 /** The map type itself. */ type()41 private XType type() { 42 return type; 43 } 44 45 /** {@code true} if the map type is the raw {@link java.util.Map} type. */ isRawType()46 public boolean isRawType() { 47 return XTypes.isRawParameterizedType(type()); 48 } 49 50 /** 51 * The map key type. 52 * 53 * @throws IllegalStateException if {@link #isRawType()} is true. 54 */ keyType()55 public XType keyType() { 56 checkState(!isRawType()); 57 return type().getTypeArguments().get(0); 58 } 59 60 /** 61 * The map value type. 62 * 63 * @throws IllegalStateException if {@link #isRawType()} is true. 64 */ valueType()65 public XType valueType() { 66 checkState(!isRawType()); 67 return type().getTypeArguments().get(1); 68 } 69 70 /** Returns {@code true} if the raw type of {@link #valueType()} is {@code className}. */ valuesAreTypeOf(ClassName className)71 public boolean valuesAreTypeOf(ClassName className) { 72 return !isRawType() && isTypeOf(valueType(), className); 73 } 74 75 /** Returns {@code true} if the raw type of {@link #valueType()} is a framework type. */ valuesAreFrameworkType()76 public boolean valuesAreFrameworkType() { 77 return FrameworkTypes.isFrameworkType(valueType()); 78 } 79 80 /** 81 * {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code 82 * Producer<V>}. 83 * 84 * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a 85 * framework type 86 */ unwrappedFrameworkValueType()87 public XType unwrappedFrameworkValueType() { 88 checkState(valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", type()); 89 return uncheckedUnwrappedValueType(); 90 } 91 92 /** 93 * {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}. 94 * 95 * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a 96 * {@code WrappingClass<V>} 97 */ 98 // TODO(b/202033221): Consider using stricter input type, e.g. FrameworkType. unwrappedValueType(ClassName wrappingClass)99 public XType unwrappedValueType(ClassName wrappingClass) { 100 checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this); 101 return uncheckedUnwrappedValueType(); 102 } 103 uncheckedUnwrappedValueType()104 private XType uncheckedUnwrappedValueType() { 105 return unwrapType(valueType()); 106 } 107 108 /** {@code true} if {@code type} is a {@link java.util.Map} type. */ isMap(XType type)109 public static boolean isMap(XType type) { 110 return isTypeOf(type, TypeNames.MAP); 111 } 112 113 /** {@code true} if {@code key.type()} is a {@link java.util.Map} type. */ isMap(Key key)114 public static boolean isMap(Key key) { 115 return isMap(key.type().xprocessing()); 116 } 117 isMapOfProvider(XType keyType)118 public static boolean isMapOfProvider(XType keyType) { 119 if (MapType.isMap(keyType)) { 120 return MapType.from(keyType).valuesAreTypeOf(TypeNames.PROVIDER); 121 } 122 return false; 123 } 124 125 /** 126 * Returns a {@link MapType} for {@code type}. 127 * 128 * @throws IllegalArgumentException if {@code type} is not a {@link java.util.Map} type 129 */ from(XType type)130 public static MapType from(XType type) { 131 checkArgument(isMap(type), "%s is not a Map", type); 132 MapType mapType = new AutoValue_MapType(type.getTypeName()); 133 mapType.type = type; 134 return mapType; 135 } 136 137 /** 138 * Returns a {@link MapType} for {@code key}'s {@link Key#type() type}. 139 * 140 * @throws IllegalArgumentException if {@code key.type()} is not a {@link java.util.Map} type 141 */ from(Key key)142 public static MapType from(Key key) { 143 return from(key.type().xprocessing()); 144 } 145 } 146